RubyでネストしたHashをオブジェクト化する方法
Ruby2系までは、ネストした階層のハッシュをオブジェクト化するには、JSON化してOpenStructを使うのが簡単だったが、 Ruby3.0からOpenStructが非推奨になってしまったため、Structでやる必要になって少しはまったのでメモ。
response = { users: [ profile: { { birthday:20010101 } } ] }
こんな感じのデータをオブジェクト化する場合は、
response_obj = JSON.parse(response, object_class: OpenStruct)
こうすればオブジェクト化できて、
p response_obj.users.first.profile.birthday # 20010101
こんな感じでアクセスできるようになっていたが、OpenStructが使えないので、Structで作る必要がある。
birthday = Struct.new(:birthday).new(20010101) profile = Struct.new(:profile).new(birthday) response_obj = Struct.new(:users).new([profile])
配列の場合はnewをする時に配列の状態で入れてあげれば(今回の場合は[profile]
)そのまま配列のオブジェクトとしてアクセスできるようになる。
Ruby On RailsでControllerからViewへのリダイレクトの際にメッセージ等レスポンスを返す方法
登録フォームなどをRailsで書いていると、登録成功、失敗それぞれのときにView側にメッセージを返したくなる時がある。 ajaxなどを使ってもできるが、flashを利用するとRailsのみで実現できる。
- controller側の例
def create # 何らかの処理 if 成功した場合 flash[:notice] = "成功メッセージ" redirect_to 成功時のリダイレクト先 else flash[:alert] = "失敗メッセージ or エラーメッセージ" redirect_to 失敗時のリダイレクト先 end end
- view側の例(slim)
- if flash[:notice] .notification.is-success = flash[:notice] - if flash[:alert] .notification.is-danger = flash[:alert]
flashをそのまま受け取って、if文で分岐し、メッセージを表示させる。
Ruby On Rails、Slimのlink_toでget以外のメソッドを送信したいとき
管理画面の改修をしており、テーブルにある行の1つを削除したいとき、
その行に削除ボタンを設置してそのまま削除処理をおこないたくなるような場面に遭遇した。
= link_to '編集', edit_user_path(user_id)
編集画面に遷移させたいなどであればrotingやcontrollerにeditメソッドなどを用意して上記のような形で良いが、
対応するcontroller側のdestroyメソッドに飛ばしてユーザー削除処理などを行いたい場合は以下のようにやる。
= link_to '削除', user_path(user_id), method: :delete, data: { confirm: '削除してよろしいですか?' }
method: :delete
を加えてあげれば意図した動きになる。dataにconfirmもつければalertで制御もできるのでより丁寧に作れる。
存在するかわからない子データを取得する場合は「&.」が便利
超基本だがよく使うのでメモ。
- users - id - name - user_profiles - id - user_id - age
上記のような1対1の関係のテーブルがある場合、Railsのモデルでuserからuser_profileのageにアクセスする場合は、
user.user_profile.age
といったようにアクセスできる。
ただ、まだuser_profileが対象のuserに存在しない場合は上記のような書き方をするとエラーになってしまう。
なのでユーザー情報入力欄などで、空の場合と存在する場合両方の可能性がある場合は、
user.user_profile&.age
とすることで存在する場合はageを取得し、そうでない場合はnilを返すようにできる。
同じようなことをするtryというメソッドもあるが、こちらの方が早い。
Docker ComposeでElasticsearchを動かそうとしてもうまく動かなかった時にやったメモ
elasticsearchをアップデートしたらうまく動かなくなった。
結論から言うと、
environment
に"bootstrap.system_call_filter=false"
を追加した。
elasticsearch: container_name: elasticsearch image: appbrewadmin/elasticsearch:7.9.3 ports: - 9200:9200 - 9300:9300 environment: - "bootstrap.system_call_filter=false" volumes: - ./tmp/docker/elasticsearch:/usr/share/elasticsearch/data:delegated
上記のような必要最低限の設定事項で起動してみたが、無事動作を確認できた。
Ruby2系をRuby3系にアップグレードしたらbootsnapのエラーがでた時の対応
Ruby2.7.5から3.0.4にあげたときrails s
を実行時にbootsnapがエラーを出した。
Railsは6.1.5。
.rbenv/versions/3.0.4/lib/ruby/gems/3.0.0/gems/bootsnap-1.13.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:17:in `require': cannot load such file -- rexml/document (LoadError)
調べると結構キャッシュを削除すれば良いと出てくるので、tmp/cache下を削除したがだめだった。
さらに調べたら、3系からrexmlがデフォルトで入らなくなったのが原因。
Gemfileに以下を追加してbundle install
したら解決。
gem 'rexml', '~> 3.2', '>= 3.2.5'
Railsアップグレード等でmini_racerやlibv8-nodeなどがビルドエラーになって更新できない問題の対応
Railsの6.0から6.1にアップグレードするだけでもかなりハマってしまったのでメモ。
bundlerを最新にする
これだけでも解決することがある。
BUNDLER_VERSION=2.3.9 gem install bundler -v ${BUNDLER_VERSION} bundle _${BUNDLER_VERSION}_ install --jobs=4 --path vendor/bundle
インストールをDocker等でコード化している場合は上記のように明記しておくと管理しやすい ※ BUNDLER_VERSIONは環境変数などにしておく
gem update --systemをする
上記とセットでした方がよりよい。ビルドをしているサーバーなどで行う。
gem update --system
プラットフォームを追加
libv8_monolith.a: No such file or directory
このようなエラーがCircle CIやLinux上のJenkinsなどでビルド中に出る場合は、
bundle lock --add-platform x86_64-linux
こちらのコマンドを実行して必要なgemを追加すると解決する場合がある。
execjsとNode.jsを使う
上記でもエラーが出る場合は、mini_racerを使わない方法が楽。 要はmini_racerはJavascriptをRailsで実行するためのものなので、 こちらで紹介されているように、execjsのgemを入れれば、最適なものを選んでJavascriptを実行してくれる。 blog.dnpp.org
※ リンク先にも説明があるが、Node.js以外でももちろん大丈夫。
CircleCIで行うときの注意点
Node.jsが入っていないイメージでビルド等している場合は入っているイメージを使う。
cimg/ruby:2.7.5-node
等