Rails5 の階段のーぼる〜

株式会社ジラフ
9 min readJun 29, 2018

--

こんにちは。ヒカカク!を担当しています大野です。

弊社のメインプロダクト「ヒカカク!」の Ruby on Rails のバージョンを 4.2.5 から 5.0.2 にアップデートしましたので、その流れを書いていきます。

Railsアップデートの流れ

おおまかな流れは以下のようになります。

  1. Railsアップグレードガイド(日本語訳版はこちら)でアップデートの流れと大きな変更点をざっと確認する
  2. Rails gem自体と関連ファイルをアップデートする
  3. テストを走らせながら、落ちている部分、DeprecationWarningが出ている部分をなおす
  4. 実際の挙動の確認

前提としてテストのカバレッジが十分であること。普段からテスト書きましょう。

実際の作業

Rails gemと関連ファイルのアップデート

まずはRails gem自体のアップデートをおこないます。

# Gemfilegem 'rails', '5.0.2'

Gemfile を修正し、

bundle update rails

を実行します。

これでRails gem自体のバージョンがアップデートされました。

次にRailsのアップデートタスクを走らせます。これは、Rails関連の設定ファイルを更新することを目的としています。主に config/ 以下のファイルが更新されます。

bundle exec rails app:update

このタスクを実行すると既存の設定ファイルが新しいバージョンに沿った形に更新されます。

実際の作業では、既存のファイルの必要な設定部分が削除されないように注意しながら、新しい更新部分を手動でマージしていくこととなります。

ここまでで、Railsの環境は整いました。では次に実際のアプリケーションコードを見ていきます。

テスト落ち & DeprecationWarning部分 を修正

以降はテストを常に走らせながら作業していくこととなります。

テストが落ちている部分は期待していた挙動と異なる挙動をしているところです。もちろん修正必須。

また、DeprecationWarningとは、「今は動いてるけど、バージョンアップしたら動かなくなるコードだよ」という警告です。放置してもいいのですが、次のバージョンアップをスムーズにするためにも修正したらいいと思います。

○ActionController::Parametersの仕様変更

コントローラーの paramsの仕様変更です。これが結構大きいかと思います。

ActionController::Parameters が HashWithIndifferentAccess (文字列でもシンボルでも値にアクセスできるハッシュ的なアレ)を継承しなくなります。

というかそもそものActionController::Parametersインスタンスのオブジェクト仕様自体が変わります。

具体的にいうと以下のような感じ。

# app/controllers/xxx_controller.rb$ params
=> { "name"=>"キリン", "email"=>"zousan@like_more.com" }

↑Rails4以前はこんな感じだったとおもいます。Rails5では、

$ params
=> <ActionController::Parameters {"name"=>"キリン", "email"=>"zousan@like_more.com"} permitted: false>

となります。見てわかる通り、 permitted: false なわけです。許可されていないのです。だから、

$ User.new(params)

これで ActiveModel::ForbiddenAttributesError が発生し、インスタンス生成ができません。ストロングパラメーターを使いましょう。

$ user_params = params.permit(:name, :email)
$ user_params
=> <ActionController::Parameters {"name"=>"キリン", "email"=>"zousan@like_more.com"} permitted: true>
$ User.new(user_params)
=> #<User id: nil, name: "キリン", email: "zousan@like_more.com">

このように permitted: true になったパラメーターでインスタンスを生成できます。

要はセキュリティーが強くなったんですなあ。

○ApplicationRecord, ApplicationJob を継承させる

ActiveRecordのモデルとActiveJobは、ActiveRecordとActiveJobを継承していたと思います。Rails5からは、それぞれ ApplictionRecordとApplicationJob を継承させます。

# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
# app/jobs/application_job.rb
class ApplicationJob < ActiveJob::Base; end

上記の2ファイルをつくることとなります。

なおこの変更は、アプリ全体のモデルの動作を1か所で変更できるようにすることが目的っぽいです。

○before_saveなどのコールバックチェーン停止条件の変更

ActiveRecord、ActiveModelのbeforeコールバックで false を返すとすべてのコールバックチェーンが中止されていました。しかしRails5から throw(:abort) と、明確に停止させる必要があります。

booleanを返すとDeprecationWarningが出るようになってた気がします。

まあこっちのが明示的でいいですかね。

○ControllerSpecの見直し

コントローラー関連のテストのヘルパーメソッドが、Rails5からrails-controller-testing gemに切り出されました。具体的には、assignsassert_template が使えなくなります。rails-controller-testing gemを追加すれば以前と同様に使うことができます。

ただRails5ではControllerSpec自体が推奨されていないようです。

これから新しく作成する Rails アプリケーションについては、 rails-controller-testing gem を追加するのはおすすめしません。 Rails チームや RSpec コアチームとしては、代わりに request spec を書くことを推奨します。 Request spec は一つのコントローラーアクションにフォーカスしますが、 controller spec とは違い、ルーターやミドルウェアスタック、Rack リクエストやレスポンスも関与します。 これによって、より現実に近い環境でテストを実行し、controller spec で発生しがちな多くの問題を避けることができます。

(参照:http://rspec.info/ja/blog/2016/07/rspec-3-5-has-been-released/)

○そもそもRSpec自体の記法でDeprecationWarningですごい

get :show, id: 123
post :create, { id: 123, name: 'キリンです' }

↑これを、

get :show, params: { id: 123 }
post :create, params: { id: 123, name: 'キリンです' }

というように変更する必要があります。

言ってしまえばリクエストパラメーターに params: と付け加えるだけですが、まあ結構めんどうです。エディタの機能を使うなど、うまくやりましょう。

○マイグレーションファイルにバージョン番号表記

# db/migrate/20180629123456_create_users.rbclass CreateUsers < ActiveRecord::Migration[4.2]
xxx
end

上記の ActiveRecord::Migration の後ろの数字です。そのマイグレーションファイルが追加されたときのRailsバージョン情報をふよしてください

最後に

なかなか長い道のりですが地道にがんばればなんとかなります。この記事のはじめの方にリンクを貼った、Railsアップグレードガイドが大変参考になるかと思います。行き詰まったら見てみましょう。

Rails5アップデートのプルリクにいただいた LGTM画像。

ふ〜じは〜 に〜っぽん い〜ちのやま〜。

告知

株式会社ジラフでは、開発をがんばる仲間を募集ちう!

--

--