パパエンジニアのアウトプット帳

30歳に突入した1児のパパエンジニアのブログ

Rails4.2から5.1へアップグレードした

お仕事で関わっているRailsアプリを4.2から5.1へアップグレードした。

もうRails4系から5系へのバージョンアップをやったブログとかかなりあるのでアレだが、

初めて自分もRailsのメジャーバージョンアップの対応をやったのでメモとして残そうと思う。

所感

あとはつらつらやった作業のメモを残すだけになってしまったので、最初にまとめというか所感を。

  • まさに辛かったの一言
  • 世の中で言われている当たり前のことをちゃんとやってないと、こういうときに牙をむくことを改めて痛感
    • ライブラリはこまめにアップデートとか、コードの書き方統一しましょうとか、テストちゃんと書きましょうとかとか
  • 最後にまとめてbundle updateやったけど影響あるときにどれが関連しているかを調べるのに苦労したので、1つ1つやったほうがよかった

辛かった話は毎月参加しているkawasaki.rbでも話して鬱憤を晴らさせてもらった。

speakerdeck.com

現状

アップグレード前のRubyRailsのバージョンは下記。

Ruby:2.3.0

Rails:4.2.6

アップグレードしてこの記事を書くまでちょっと空いてしまったが、

アップグレード検討を始めたときの最新版などを調査してRubyRailsを下記にすることとした。

Ruby:2.4.2

Rails:5.1.4(ver4は4.2.9, 4.2.10.rc1がでてる)

事前調査

まずはRails5で何が変わるかなどを公式のリリースノートを見た。

https://railsguides.jp/5_0_release_notes.html

https://railsguides.jp/5_1_release_notes.html

アップグレードの方針

初めてのメジャーバージョンアップなのでどうやるのが良いのかを色々調べた。

まずは、公式のアップグレードガイド。

https://railsguides.jp/upgrading_ruby_on_rails.html


そして、先人の知見を見て回る。

https://qiita.com/yamamuteki/items/cfc7bb9999518bc5b19c

https://qiita.com/jnchito/items/fa680e104d4bf49ae06f

http://blog.rista.jp/entry/2017/06/11/190616

https://dev.classmethod.jp/server-side/ruby-on-rails-5-0-upgrade/

http://r7kamura.hatenablog.com/entry/2016/12/10/045755

http://blog.spacemarket.com/code/how-to-upgrade-rails5-1-2/

http://tech.grooves.com/entry/2016/07/01/184458

https://blog.mwed.info/posts/rails50.html

https://qiita.com/zenpou/items/950432bae246063786e8

http://akasata.com/articles/319

https://doruby.jp/users/bibio/entries/Ruby-on-Rail-4-2-%E3%81%8B%E3%82%89-5-1-%E3%81%B8%E7%A7%BB%E8%A1%8C%E3%81%97%E3%81%9F%E9%9A%9B%E3%81%AE%E3%83%A1%E3%83%A2

https://qiita.com/kenchan0130/items/f5ae55a6e23268238a44

色々と調べた結果、いきなり最新の5.1にするのではなく少しずつ刻みながらアップグレードしたほうが安全そうなので下記の流れでやる方針とした。

  • Rails4.2系の最新(4.2.6→4.2.9)へ
  • Rails5.0系(5.0.6)へ
  • Rails5.1系(5.1.4)へ
  • Rubyを2.3.0から2.4.2へ

gemも全てをいきなりバージョンアップするのではなく、まずはRailsのアップグレードに必要なものだけを対応して、その他はRails5.1へアップグレード対応後にやるようにした。

アップグレード作業

4.2系の最新版へ

specの実行

まず現段階でテストがオールグリーンなのを確認。

Gemfileの更新

1.Gemfileのrailsのバージョンを変更

gem 'rails', '4.2.6'
↓
gem 'rails', '4.2.10'

2.bundle update railsを実行

railsのアップデートは問題なく完了

3.specの実行

ここでエラーやWarningがないかを確認する。

Warningが出た。

Sprocketsが3.6から3.7にアップデートされたことによってsass-railsにSprocketsで非推奨の記述がされているらしい。

DEPRECATION WARNING: Sprockets method `register_engine` is deprecated.
Please register a mime type using `register_mime_type` then
use `register_compressor` or `register_transformer`.
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
 (called from block (2 levels) in <class:Railtie> at /app/tmp/bundler/ruby/2.3.0/gems/sass-rails-5.0.3/lib/sass/rails/railtie.rb:57)
DEPRECATION WARNING: Sprockets method `register_engine` is deprecated.
Please register a mime type using `register_mime_type` then
use `register_compressor` or `register_transformer`.
https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
 (called from block (2 levels) in <class:Railtie> at /app/tmp/bundler/ruby/2.3.0/gems/sass-rails-5.0.3/lib/sass/rails/railtie.rb:58)

なので、sass-railsもアップデートする必要がある。

bundle update sass-rails アップデート後、再度specを実行するとWarningが出なくなった。

rake rails:update

マイナーバージョンアップなので特にconfigとかに変更はないと思うが一応やった。

案の定特に変更はなかった。

5.0系の最新版へ

5.0系の最新版5.0.6へバージョンアップする

Gemfileの更新

1.Gemfileのrailsのバージョンを変更

gem 'rails', '4.2.10'
↓
gem 'rails', '5.0.6'

2.bundle update railsを実行

Bundler could not find compatible versions for gem 'xxx'との長い戦い。。。

結局色々bundle updateに含めて下記のようになった

bundle update rails simple_form coffee-rails devise rspec-rails slim-rails guard-rspec jquery-rails

jquery-railsはbootstrapの関連ライブラリやテーマの依存関係もあるのでここでは最小限のアップデートしかしなかった。

3.specの実行

rspecをバージョンアップしたので、deprecateエラーが出る。。。

DEPRECATION WARNING対応

  • rspecのgetやpostなどでparamsの指定が変わる
DEPRECATION WARNING: Using positional arguments in functional tests has been deprecated,
in favor of keyword arguments, and will be removed in Rails 5.1.

下記のような書き方をしないといけないらしい。

get :index, {name: 'tom'}
↓
get :index, params: {name: 'tom'}

適当に正規表現で置換してみたけど、記法がばらばらで結局都度spec実行しながら1つずつ対応していかなければならず辛かった。。

  • deviseのアップデートによる変更対応
DEPRECATION WARNING: [Devise] including `Devise::TestHelpers` is deprecated and will be removed from Devise.
For controller tests, please include `Devise::Test::ControllerHelpers` instead.
 (called from <top (required)> at /app/spec/xxx/xxxx_spec.rb

このDEPRECATION WARNINGが大量に出ている。

なので、rspecでDevise::TestHelpersを使っている箇所をDevise::Test::ControllerHelpersに変更してやる必要がある。

grepしてみるとrails_helper.rbにしかなかったのでその1箇所を修正した。

  • xxx_filter対応
DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. 

これはcancancanとtwo_factor_authenticationのバージョンが古くて内部で使っていたみたいなので最新にバージョンアップした。

※このtwo_factor_authenticationのアップデートが後に牙を向くことになる。。。

  • xhr :getなどの記法変更 xhrの書き方が変わった
xhr :get, :index
↓
get :index, xhr: true
DEPRECATION WARNING: Accessing mime types via constants is deprecated. Please change `Mime::JSON` to `Mime[:json]`. (called from require at /usr/local/lib/ruby/gems/2.3.0/gems/bundler-1.11.2/lib/bundler/runtime.rb:77)

jbuilderが利用しているようなのでアップデートした

  • raise_in_transactional_callbacksがなくなる
DEPRECATION WARNING: ActiveRecord::Base.raise_in_transactional_callbacks= is deprecated, has no effect and will be removed without replacement. (called from <top (required)> at /app/config/environment.rb:5)

application.rbにあるraise_in_transactional_callbacksはもう不要になる

  • alias_method_chainが使えなくなる
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super.

prepend使うように修正した

DEPRECATION WARNING: uniq is deprecated and will be removed from Rails 5.1 (use distinct instead)
  • render :nothingが使えなくなる
DEPRECATION WARNING: `:nothing` option is deprecated and will be removed in Rails 5.1. Use `head` method to respond with empty response body.
  • paramsがHash継承ではなくActionController::Parametersオブジェクトになる
DEPRECATION WARNING: #to_hash unexpectedly ignores parameter filtering, and will change to enforce it in Rails 5.1. Enable `raise_on_unfiltered_parameters` to respect parameter filtering, which is the default in new applications. For the existing deprecated behaviour, call #to_unsafe_h instead.

DEPRECATION WARNING: Method map is deprecated and will be removed in Rails 5.1, as `ActionController::Parameters` no longer inherits from hash. Using this deprecated behavior exposes potential security problems. If you continue to use this method you may be creating a security vulnerability in your app that can be exploited. Instead, consider using one of these documented methods which are not deprecated: http://api.rubyonrails.org/v5.0.6/classes/ActionController/Parameters.html

内部のAPI連携でstrong parameter対応サボっているところやHashのつもりでその後の処理をしようとしている箇所で発生していた。

結局ここでDEPRECATION WARNINGが出るものは幸せで、外部連携とかでモック化していてテストではエラーやWARNINGにならないところが多く後々の打鍵テストで色々見つかった。。。

  • redirect_to :backが使えなくなる
DEPRECATION WARNING: `redirect_to :back` is deprecated and will be removed from Rails 5.1. Please use `redirect_back(fallback_location: fallback_location)` where `fallback_location` represents the location to use if the request has no HTTP referer information.

redirect_back使うように修正

rails app:update

diffを見ながらアップデートした。

rspecのエラー対応

  • redirect_to request.refererのエラー

http://haito.hatenablog.com/entry/2017/07/13/150454

https://stackoverflow.com/questions/12591763/how-do-i-set-a-request-referrer-inside-my-rspec

なにが正解かいまいちわからないが、とりあえずrequest.env['HTTP_REFERER'] = '/test'のようにしてテストが通るようにした。

allow(request).to receive(:referer).and_return('/test')でrefererのスタブ化ができなくなっていた。

そもそもredirect_to request.referer自体がまずくてredirect_back(fallback_location: root_path)とかにする必要あると思っている(NOTE

  • rspecで空のパラメータがnilになる
put :update, params: {id: "12345678", book: {}}

とやっている箇所でparams[:members]がnilになってしまう。

put :update, params: {id: "12345678", book: {tags: []}}としてもidしかコントローラにこない。。。

4.2ではログのparametersに{id: "12345678", book: {}}と出ていたが、5.0では{id: "12345678"}になっていた。

深くは追ってないがputなりでからのパラメータを送らなくなったか受け取るrails側で削除するようにしたのだろう。

actionpack/lib/action_controller/test_case.rbがrailsのバージョンアップでかなり変わったので、その変更で空のパラメータは送らなくなった?

  • sessionがgetなど毎にリセットされるようになった?
get :index, params: {code: "000001"}

get :index

みたいに1つ目のgetでsessionにcodeを覚えさせて2つ目のgetでもsessionが保持されていたみたいだけど、されなくなったみたい。

rails db:migrateの実行

マイグレーションのファイル追加は無いけどrails db:migrateを実行するとdb/schema.rbが変更される。

add_indexがなくなって各テーブル内のt.indexに変わる。

developmentで動かしてみてのエラー

  • Attempting to generate a URL from non-sanitized request parameters! An attacker can inject malicious data into the generated URL, such as changing the host. Whitelist and sanitize passed parameters to be secure.

エラー箇所を見るとkaminariのpaginate @booksみたいにページネートを表示するところでエラーになっている。

kaminariをアップデートしたら解決した。

その他

  • ApplicationRecordクラスやApplicationJobクラスを作ってRails5のお作法に合わせた

5.1系の最新版へ

Gemfileの更新

  1. Gemfileのrailsのバージョンを変更
gem 'rails', '5.0.6'
↓
gem 'rails', '5.1.4'


  1. bundle update railsを実行

activerecord-session_storeの依存関係で怒られたので

bundle update rails activerecord-session_store

rails app:update

diffを見ながらアップデートした。

new_framework_defaultsについては下記を見ておいたほうがいい。

http://y-yagi.tumblr.com/post/144067860535/rails-5%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%81%9Finitializer%E3%81%AE%E3%81%BE%E3%81%A8%E3%82%81 http://y-yagi.tumblr.com/post/160114728555/rails-51%E3%81%A7%E8%BF%BD%E5%8A%A0%E3%81%95%E3%82%8C%E3%81%9Fconfig%E3%81%BE%E3%81%A8%E3%82%81


3. specの実行

またdeprecation warningが。。。

DEPRECATION WARNING対応

  • halt_callback_chains_on_return_falseは使えなくなる
DEPRECATION WARNING: ActiveSupport.halt_callback_chains_on_return_false= is deprecated and will be removed in Rails 5.2. (called from <top (required)> at /app/config/initializers/new_framework_defaults.rb:25)

halt_callback_chains_on_return_falseは使えなくなるので削除した

  • belongs_toのclass_nameオプションにクラス名の文字列を指定しなくてはいけなくなる
DEPRECATION WARNING: Passing a class to the `class_name` is deprecated and will raise an ArgumentError in Rails 5.2. It eagerloads more classes than necessary and potentially creates circular dependencies.

クラス名していからクラス名の文字列に変更

  • ifやunlessオプションに文字列の指定ができなくなる
DEPRECATION WARNING: Passing string to be evaluated in :if and :unless conditional options is deprecated and will be removed in Rails 5.2 without replacement. Pass a symbol for an instance method, or a lambda, proc or block, instead.

シンボルかlambdaなどを使う形式に変える

  • schema_migrations_table_nameが使えなくなる
DEPRECATION WARNING: schema_migrations_table_name is deprecated and will be removed from Rails 5.2 (called from block (2 levels) in <top (required)> at /app/spec/spec_helper.rb:87)

DatabaseRewinder.clean_allとしているところでエラーになっているので、database_rewinderをアップデートした。

rails db:migrateの実行

マイグレーションのファイル追加は無いけどrails db:migrateを実行するとdb/schema.rbが変更される。

careate_tableにid: :serialが付いた。

あとは見栄えをそろえるためにカラム名やnullオプションなどなどにスペースをいくつも入れて整形していた箇所が基本スペース1つになったみたい(なんでや・・・ )

  create_table "books", force: :cascade do |t|
    t.string  "title",    null: false
    t.integer "quantity", null: false, default: 0
  end
↓
  create_table "books", id: :serial, force: :cascade do |t|
    t.string "title", null: false
    t.integer "quantity", null: false, default: 0
  end

ActiveRecord::Migrationのバージョン指定対応

とりあえず全て[4.2]をつけた

今後[5.1]を使いたいなと思ったがidやxxx_idをbigintに対応するのが必要なのでここでは見送った。

bundle update

そのほかのgemも最新版にした。

しかし、bootstrap-datepicker-railsとbootstrap-sassは最新にすると(というか現行バージョン以外だと)表示が崩れてしまう。。

バージョンアップすることによってかなり変わってしまい、どうしたら回避というか正常にできるか目処がたたなかった(自身の力不足)のでこの2つだけは、現行のままで行くことにした。

その他、capistranoもバージョンアップして少し書き方変わるところがあったのでその対応などした。