Help us understand the problem. What is going on with this article?

Rails 5 アップデートへの道

More than 1 year has passed since last update.

とあるアプリを Rails 4.2.x から Rails 5.0.0.1 へアップデートしたので、その記録を残そうと思います。

前提

Ruby のバージョンが 2.2.2 以上でなければ、Rails 5 は動作しません。
2.2.2 未満を使用している場合は、まずは Ruby のバージョンを上げて動作を確認を行うことをオススメします。

ライブラリのバージョンアップ

Rails 4 系に依存してるライブラリを Rails 5 系に対応しているものにしたいため、

bundle update

を行います。
この方法は全ての gem をアップデートしてしまうため、
関連するものだけをアップデートしたい場合は個別に指定しましょう。

Rails 5 へのアップデートの原因の切り分けを行うため、
この時点でテストが全て通過していることを確認することをオススメします。

Rails 5 の gem をインストール

# Gemfile
gem 'rails', '5.0.0.1'

に変更します。

bundle update rails

これでうまくインストール出来ない場合は、依存しているライブラリが Rails 5 対応してないと考えられます。
issue 立てるなり PR を出すなりして対応しましょう。
OSS に貢献するチャンス :thumbsup:

Rails 5 の設定に対応させる

設定周りが追加、変更になっているため、更新しないといけないですが、
Rails にはこの更新をサポートしてくれるコマンドが用意されています。

rails app:update

diff を見つつ、問題なければ上書きして、
問題ありそうであれば、うまく差分を吸収していきましょう。

routes.rbapplication.rb などにも変更が入るので、慎重に。

各ファイルの調整

上記だけでテストが通れば問題ないのですが、
いくつか API が変更されているため、そうは問屋が卸さない感じです。

アプリケーションのファイルにも少し手を加える必要が出てきます。
また、多数の DEPRECATION WARNING が出てくると思われますので、
地道に 1 つずつ潰して行きましょう。

◯◯::Base の継承が変更

  • ActiveRecord::Base
    • ApplicationRecord
  • ActiveJob::Base
    • ApplicationJob
  • ActionMailer::Base
    • ApplicationMailer

上記の 3 つが直接継承からもう一層挟むようになりました。
これで Base クラスにモンキーパッチ当てずに済みますね!

解決方法

ActiveRecord::Base が少し特殊です。
普通に継承してしまうと、テーブルとして認識されてしまうため、

# application_record.rb
class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end

上記のように self.abstract_class = true を記載しましょう。

xxx_filter の非推奨

before_filterafter_filter などが非推奨になりました。

解決方法

xxx_action に変更しましょう。

env の直接参照が非推奨

ActionController を継承したクラス内での env を使用して、
rackenv へのアクセスが非推奨となりました。

解決方法

request.env から取得するようにしましょう。

plain/text の render 方法が変更

plain/text で render する場合、
render text: での指定が非推奨となりました。

解決方法

render plain: にしましょう。

response.headersObject の変更

response.headersHash オブジェクトでしたが、
ActionDispatch::Response::Header オブジェクトに変更になりました。
DelegateClass(Hash) を継承しているので、Hash の子クラスではありません。
そのため、

expect(response.headers).to include { 'Authorization' => 'Bearer sample_token' }

のように Hash として扱っていた場合に影響が出てきます。

解決方法

Hash として扱いたい場合は、
response.headers.to_h を呼び出し、
Hash オブジェクトに変換しましょう。

response.headers= API の消失

response.headers= の API が無くなったため、
ヘッダーを直接変更することができなくなりました。

解決方法

response.headers[] を使用して 1 つずつ変更していきましょう。

errors[] の非推奨

モデルの errors[] を使用してエラーの追加を行うことが非推奨となりました。

解決方法

errors.add で変更を行うようにしましょう。

リクエストの JSON パーサーの独自定義方法の変更

今までリクエストの JSON パーサーを独自に定義する場合、

Rails.application.config.middleware.swap(
  ::ActionDispatch::ParamsParser, ::ActionDispatch::ParamsParser,
  ::Mime::JSON => proc do |raw_post|
    ::ActiveSupport::JSON.decode(raw_post).with_indifferent_access
  end
)

のように middleware にかます方法が利用できましたが、この方法が使用できなくなりました。

解決方法

ActionDispatch::Request.parameter_parsers にパーサーの定義が入るようになったため、

ActionDispatch::Request.parameter_parsers[:json] = -> (raw_post) do
  ::ActiveSupport::JSON.decode(raw_post).with_indifferent_access
end

上記のように JSON パーサーを定義(代入)するようにしましょう。

migration のバージョン指定

migration にバージョンの指定が必要になりました。
production 環境では問題ないのですが、
CI でのテストなど、 DB がリセットされており、再度 migration を走らせると警告が出てしまいます。

解決方法

ActiveRecord::Migration[4.2] としましょう。

json および jsonb 型カラムが存在する migration 時にデフォルト値の解釈が変更

今までは json および jsonb 型カラムのデフォルト値に object を入れる際は

create_table :posts do |t|
  t.jsonb :settings, default: '{}'
end

のように文字列で指定していましたが、シリアライズされずに設定されるようになりました。
既にプロジェクトに存在しておりかつ適用している migration ファイルに関しては production に影響はないですが、
開発時に rails db:migrate:reset などを行った場合、
scheme.rb が更新されてしまうので、対応しておくことをオススメします。

解決方法

create_table :posts do |t|
  t.jsonb :settings, default: {}
end

Ruby のオブジェクトの状態でデフォルト値を設定するようにしましょう。

alias_method_chain の使用が非推奨

モンキーパッチなどを行う際、
モンキーパッチする前のメソッドを参照できるように alias_method_chain というメソッドが用意されてしましたが、非推奨になりました。

解決方法

Object.prepend を使用するようにしましょう。
具体的な例については Techscore さんの Ruby2.0のModule#prependは如何にしてalias_method_chainを撲滅するのか!? に詳しく書かれております。

ActionController::TestCase が非推奨

クラス名を言われても何を指しているのかピンと来ない方もいるかと思います。
controllerrequest のテストを行う際に、

post '/post', { title: 'sample' }, { 'Authorization' => 'Bearer sample_token' } 

このようにリクエストのテストを実現していたと思いますが、この API が変更になったと考えて良いと思います。

解決方法

公式でも言及されているように、
ActionDispatch::IntegrationTest を使用しましょう。

具体的には

post '/post', params: { title: 'sample' }, headers: { 'Authorization' => 'Bearer sample_token' } 

としましょう。
path 以外はキーワード引数になりました。

middleware の差し込みのクラス名の文字列指定が非推奨

今まで読み込み順の関係もあり、クラス名を指定する場合は文字列で指定している方が多かったかと思いますが、こちらが非推奨になりました。

# application.rb
config.middleware.insert_before 0, 'Rack::Cors' do
end

解決方法

# application.rb
config.middleware.insert_before 0, Rack::Cors do
end

クラス名をオブジェクトの状態で渡しましょう。

ActionController::ParametersHash 継承ではなくなった

今回の変更で一番の鬼門はこれと言っても過言ではないかと(個人的に)思っています。
ActionController::ParametersHash 継承でなくなりました。

入れ子になっているパラメータ(オブジェクト)も ActionController::Parameters オブジェクトになっています。

params.merge は必ず引数に Hash オブジェクトを取るようになったので気をつけてください。

また、to_hHash オブジェクトに変換するわけではなく、

params[:title]
# => 'hoge'
params[:sub_title]
# => 'fuga'
params.permit(:title).to_h
# => { 'title' => 'hoge' }

上記のように permitted なパラメータのみ Hash の attributes に含むようになりました。

解決方法

ActionController::Parameters 同士を merge する際は
Hash オブジェクトに変換してください。

key が不定なパラメータを受け取る場合は、
to_unsafe_h というメソッドが用意されているのでこちらを使用します。

unsafe とあるように、安全でない可能性があるため、
用法用量を守り正しくお使いください。

まとめ

Rails 5 にすることで、様々な新機能が使用できるようになります。
個人的には

  • OR の発行
    • 合わせてpolymorphic のクエリの改善
  • ActionCable
  • rails-api
  • migration の mysql 大幅サポート

辺りが、直近恩恵を受けています。

一部ベンチによると、ActiveRecord 周りなど、少し遅くなったりしてるようですが、
マイナー及びパッチバージョンアップで改善されると思います。

みなさんもステキな Rails 5 ライフをお送りください。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした