Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

管理画面のRailsバージョンをRails4からRails5に上げた話

こんにちは、広告技術部の倉澤です。
普段は広告配信のための管理画面を作ったりしています。 今回はその管理画面をRails5にアップデートした話を書きたいと思います。

この管理画面の first commit は2013年9月17日、 Rails Wayにそってないコードもあり、それなりにレガシー感のあるシステムです。

きっかけは以下プルリク

Railsの4.2がメンテされなくなるとのことだったので
そろそろ重い腰をあげる時がきたということで取りかかりました。

やったことを簡単にまとめると以下な感じです。

では、詳細を書いていこうと思います。

1. Rails以外のGemをアップデートする

はじめはそのまま Rails のアップデートを試みたんですが、依存関係の問題で簡単には上げられず。 1個ずつ依存解決していっても終わる気しなかったので Gemfile.lock を削除してRockにアップデートすることにしました。

しかし、これをすると変更が大き過ぎるのでRails以外のGemアップデートだけ先にリリースしました。 もちろん問題ないかしっかり確認する必要があり、やることが結構増えましたが、 氷漬けにされたGemをアップデートできたのでよかったと思います。

2. Rails5にアップデート

他のGemをアップデートしたのであとはRails5にアップデートするだけです。 ただし、些末なGemでRails5に対応していないものもあったのでそれは一旦forkして対応しました。
その他、deprecation warning がでる ので shoulda-matchers gem を rails-5 ブランチに変更。

Rails5にすることによって不要になる2つのGemも削除しました。

  • quiet_assets
    • Rails5ではデフォルトの挙動になっているため
  • activerecord-in_batches
    • Rails5 の ActiveRecord::Relation#in_batches を Rails4へ backport するためのgemであるため

今までありがとう。

3. アップデートタスクを実行

アップデートタスク rails app:update で新しいバージョンでのファイル作成や既存ファイルの変更を対話形式で行えます。 既存ファイルは結構コンフリクトしたので頑張って修正しました。
また new_framework_defaults.rb が作成され、Rails 5の新機能はオフにしています。 一気に変えずに済むのはありがたいですね。

また、ここで以下の設定も変更しました。

  • activerecord-refresh_connection gem の 設定をRails5に対応させる
  • config.raise_in_transactional_callbacks = true の設定がいらなくなったため削除

4. Rails 4.2からRails 5.0へのアップグレードを眺めて必要そうな変更を入れる

railsguides.jp

ここでやった大きなことは以下3つです。

  • ApplicationRecord を作成して Active Record モデルから継承するように変更
  • ApplicationJob を作成して Active Job から継承するように変更
  • rails-controller-testing gem を追加

また「 ActionController::Parameters は今後 HashWithIndifferentAccess を継承しない 」による変更箇所は数多くあったのでこれは次に書くテストで落ちた箇所を修正していきました。

5. テストを通す

テストを通しました。
落ちたところを頑張ってデバッグするだけです。300個くらい落ちてました。
全てではないですが少し列挙してみます。

  • 前述した「 ActionController::Parameters は今後 HashWithIndifferentAccess を継承しない 」対応
    • 一番多かった修正はこれ
    • params を Hashとして利用している箇所で to_h or to_unsafe_h で変換
      • to_hpermit されている値しか変換できないので permitしていない箇所は to_unsafe_h を使用しました。
      • (もちろん permit すべきだけど、この対応では to_unsafe_h を選択しました。)
    • view の link_toparams がそのまま渡されている箇所があったので to_unsafe_h で変換
      • そのまま渡すとエラーが出るようになっていた。
      • (行儀が悪いけど同上)
  • ActiveRecordの collection_singular_ids=(ids), collection<<(object, ...) で引数に不正な値を入れた場合のExceptionが変わったので対応
    • 以前 ActiveRecord::RecordNotFound が出ていた箇所で ActiveRecord::AssociationTypeMismatch が出ていた
  • Relation#to_a が dup した値を返すようになっていたので対応: https://github.com/rails/rails/pull/23794

6. deprecation warning が大量に出たので対応する

deprecation warning を直しました。 テスト時のログが大変なことになってしまうので頑張って直しました。
こちらもいくつか列挙します。

  • ActionController::Parameters の非推奨メソッドの使用箇所で to_h で Hashに変換
  • ActiveRecord の delete_all に 条件を渡していた箇所を where(conditions).delete_all に変更
  • render text:render plain: に変更
  • render :nothingrender body:nil に変更
  • Active Record の query に Class を渡していた箇所を Class名の文字列を渡すように変更: https://github.com/rails/rails/commit/c0609dd0f0f0de604ac1ffeffdf5e3e0e7356b35
  • Active Record の uniqdistinct に変更
  • envrequest.env に変更
  • テストコードでもかなり出てたけど割愛

7. 不安なので画面からもテスト

Rspec は通ってますがそれだけでは万全だとは思えなかったので画面からもテストしました。 結果から言うとやってよかったです。

Rails5から submit_tag にデフォルトで data-disable-with がつくことなり、画面がリロードされるまでボタンがdisabledになっていました。 基本大丈夫だしありがたい機能なんですが、CSV出力に submit_tag を使っている箇所があり、そこでは画面リロードがおこらず disabled のままになっていました。 一旦は config.action_view.automatically_disable_submit_tag = false の設定を application.rb に書いてデフォルトのこの挙動を無効にしています。

また、いくつかエッジケースでバグが見つかりました。 この辺は Rspec でテストできるようにしないといけない点ですね。

気をつけた点

以上でやったことはだいたい書けたかなと思います。
注意した点を書くとすると

  • commit 粒度に気をつける
  • リファクタリングをしない
  • こまめに rebase

ですかね。

どうしても変更点が多くなるため、レビュアーが大変だと思ったので commit粒度には気をつけました。 だいたいは上に列挙した粒度よりちょい細かいくらいのコミットログにしています。

また、機能開発は並行して進んでいたのでそれとコンフリクトしないようにも注意して、 変更点をできるだけ少なくする、できるだけ早くリリースするためにリファクタリングはしないようにしました。 変更点が少なければレビューもしやすいですしね。

(この考えから行けば Rails5以外のgem update はやらない方がよかったのですが、先に別プルリクとしてリリースしたのでOKとしました。)

おまけ

今回でやっぱり Gemはこまめにアップデートしておかないと大変だと学んだので 今後は Gem のアップデートをできるだけ自動化できるように dependabot を導入する予定です。

また、フロントでまだ CoffeeScript が使われている状態なので sprockets-es6 を使って とりあえず es6を書けるようにしました。
今後改善していきたいです。

そして

github.com

Rails6の開発も始まったのでRails6が出たらすぐアップデートできるように頑張って行きましょう!

そんな広告技術部ではRails管理画面に限らず広くサーバーサイド開発してくれる仲間を募集中です!
ご興味あるエンジニアの方は下記からぜひ応募してみてください!

https://hrmos.co/pages/1009778707507720193/jobs/0000003hrmos.co