Rails 4.2 -> Rails 5.0 アップデートメモ: Rails update (6)

はじめに

さて、また大変なメジャーアップデートです。かなりの変更がありますので、ゆっくりやっていきましょう。Ruby は最低限の 2.2.2 までは上げています。

Rails のアップデート

まず、Gemfile の rails を5.0 の最終である 5.0.7.2 に変更します。

gem 'rails', '5.0.7.2'

bundle update します。

bundle update

相変わらず、include でエラーが出るので外した上で、update します。5.0 からは rails という namespace が deprecated となったので、コマンドが変えておきます。

env THOR_DIFF=vimdiff bin/rake app:update

ApplicationRecord の作成と、継承の変更

ApplicationRecord を追加するとともに、全部の app/models/*.rb を修正する必要があります。これはいつもように vim のマクロで一括変換できそうです。

Rails 4.2のActive RecordモデルはActiveRecord::Baseを継承していました。Rails 5.0では、すべてのモデルがApplicationRecordを継承するようになりました。

アプリケーションのコントローラーがActionController::Baseに代わってApplicationControllerを継承するように、アプリケーションのすべてのモデルがApplicationRecordをスーパークラスとして使うようになりました。この変更により、アプリケーション全体のモデルの動作を1か所で変更できるようになりました。

Rails 4.2をRails 5.0にアップグレードする場合、app/models/ディレクトリにapplication_record.rbファイルを追加し、このファイルに以下の設定を追加する必要があります。

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

最後に、すべてのモデルがApplicationRecordを継承するように変更し、動作を確認してください。

throw(:abort) によるコールバックチェーンの停止

コールバックで false を返すと、その後の処理が停止していましたが、Rails 5.0 からは明示的に throw(:abort) をする必要があります。これも vim のマクロで置き換えしてしまいます。

Rails 4.2では、Active RecordやActive Modelで「before」系コールバックがfalseを返すと、すべてのコールバックチェーンが停止する仕様でした。この場合、以後「before」系コールバックは実行されず、コールバック内にラップされているアクションも実行されません。

Rails 5.0ではこの副作用が修正され、Active RecordやActive Modelのコールバックでfalseが返ってもコールバックチェーンが停止しなくなりました。その代わり、今後コールバックチェーンはthrow(:abort)で明示的に停止する必要があります。

before_filter → before_action の修正

アップグレードガイドには書いていませんが、リリースノートの非推奨のところに書いてありました。警告がうるさいので、このバージョンで、before, after ともに修正しておきます。

DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. (called from <class:ApplicationController> at /opt/webcitc/app/controllers/application_controller.rb:3)

filterコールバックをすべて非推奨に指定。今後は*actionコールバックを使用。 (Pull Request)

hide_action の削除

また、hide_action でエラーになりました。https://apidock.com/rails/ActionController/HideActions/ClassMethods/hide_action を見ると、5.0 で亡くなったようです。自分で書いた記憶がないので、業者が追加したものだと思います。これは普通に private メソッドにすればいいだけですね。

This method has been completely removed from Rails 5 onwards

Completely removed from Rails from 5 onwards. See issue: github.com/rails/rails/issues/18336

Just remove from your codebase, or protect with private keyword

ヘルパーメソッドの一部をrails-controller-testingに移転

bin/rspec したところ、以下のエラーが出ました。

      NoMethodError:
        assert_template has been extracted to a gem. To continue using it,
                add `gem 'rails-controller-testing'` to your Gemfile.

これですね。とりあえず、rails-controller-testing を入れればいいだけなので、Gemfile を修正します。

assignsメソッドとassert_templateメソッドはrails-controller-testing gemに移転しました。これらのメソッドを引き続きコントローラのテストで使いたい場合は、Gemfileにgem 'rails-controller-testing'を追加してください。

positional arguments の修正

これも 5.1 からの削除ですが、DEPRECATION WARNING を消しておきます。引数を params というハッシュに変更する必要があるようです。これも vim のマクロでなんとかなりそうです。

DEPRECATION WARNING: Using positional arguments in functional tests has been deprecated,
in favor of keyword arguments, and will be removed in Rails 5.1.

Deprecated style:
get :show, { id: 1 }, nil, { notice: "This is a flash message" }

New keyword style:
get :show, params: { id: 1 }, flash: { notice: "This is a flash message" },

Time 型のタイムゾーンについて

params の修正をしていたら、あるファイルで以下の警告が出ました。Rails 5.0 からは Time もタイムゾーンを考慮するようになるとのことです(Rails 5.1 から time 型の列もタイムゾーン考慮するようになるとのこと - 飲んだり寝たり)。ここを見ると単に Time と書いた時でも、Time.zone に書き換えるとのこと。

DEPRECATION WARNING: Time columns will become time zone aware in Rails 5.1. This
still causes `String`s to be parsed as if they were in `Time.zone`,
and `Time`s to be converted to `Time.zone`.

最近書いたコードはみんな Time.zone と書いていますが、過去のものは Time で書かれたものが多いです。とりあえずテストを通すため、Time.zone への書き換えはしないでおきます。ただ、内部で JST に置き換える無駄な処理が多くの場所で入っているので、最新版になったら修正することにします。

config.active_record.time_zone_aware_types = [:datetime]

reload に関する修正

これまで、関連の再読み込みをするときに obj.hoges(true)obj.foo(true) のようにして reload をしていましたが、この部分で以下の警告が出ていました。これらはobj.reload.hogesobj.reload_fooのように修正する必要があるようです。これも(true)で全検索して潰していこうと思います。

DEPRECATION WARNING: Passing an argument to force an association to reload is now deprecated and will be removed in Rails 5.1. 
Please call `reload` on the result collection proxy instead. 

params[:hoge] → params['hoge'] の修正

失敗系のテストで params[:hoge] を nil などにするテストをしていました。params のキーが文字列に変わっているようなので、失敗テストがことごとく失敗しています。これもエラーになった場所からマクロで修正してしまいます。

Active Recordのbelongs_toはデフォルトオプションで必須

belongs_to は必須になり、null になる場合には、「optional(true)」が必要になります。 新しいアプリケーションでは必須ですが、既存のものは config を書き換えない限りはまだこのままいけます。とりあえずデフォルトが true になるまで、対応はペンディングします。

関連付けが存在しない場合、belongs_toでバリデーションエラーが発生するようになりました。

新しいアプリケーションでは、このデフォルト設定が自動で有効になります。この設定を既存のアプリケーションに追加するには、イニシャライザでこの機能をオンにする必要があります

config.active_record.belongs_to_required_by_default = true

おわりに

細かいことはまだありそうですが、テストは少しずつ修正しながらも全部通すことができました。メジャーアップデートで、修正箇所が山のようにあったので、流石に 1日仕事になりました。時間は少し伸びたくらいであまり変わりませんでした。

Finished in 12 minutes 5 seconds (files took 7.23 seconds to load)
7726 examples, 0 failures, 98 pending

(12/29追記) Segmentation fault の原因が hpricot だとわかったので、 Ruby 2.4.5 でやり直してみました。時間はほぼ変わりませんでした。

Finished in 12 minutes 6 seconds (files took 5.5 seconds to load)
7726 examples, 0 failures, 98 pending

gem の推移はこんな感じです。

gem_name ver4.2 ver5.0 changed
actioncable 5.0.7.2 +
actionmailer 4.2.11.3 5.0.7.2
actionpack 4.2.11.3 5.0.7.2
actionview 4.2.11.3 5.0.7.2
activejob 4.2.11.3 5.0.7.2
activemodel 4.2.11.3 5.0.7.2
activerecord 4.2.11.3 5.0.7.2
activesupport 4.2.11.3 5.0.7.2
arel 6.0.4 7.1.4
bcrypt 3.1.16 3.1.16 =
better_errors 2.9.1 2.9.1 =
binding_of_caller 0.8.0 0.8.0 =
brakeman 4.4.0 4.4.0 =
builder 3.2.4 3.2.4 =
choice 0.2.0 0.2.0 =
ci_reporter 2.0.0 2.0.0 =
coderay 1.1.3 1.1.3 =
coffee-rails 4.2.2 4.2.2 =
coffee-script 2.4.1 2.4.1 =
coffee-script-source 1.12.2 1.12.2 =
concurrent-ruby 1.1.7 1.1.7 =
crass 1.0.6 1.0.6 =
database_cleaner 1.8.5 1.8.5 =
debug_inspector 0.0.3 0.0.3 =
devise 3.5.10 4.0.0.rc2
devise-encryptable 0.2.0 0.2.0 =
devise_ldap_authenticatable 0.8.7 0.8.7 =
diff-lcs 1.4.4 1.4.4 =
docile 1.3.4 1.3.4 =
dotenv 2.7.6 2.7.6 =
erubi 1.10.0 1.10.0 =
erubis 2.7.0 2.7.0 =
execjs 2.7.0 2.7.0 =
factory_bot 4.11.1 4.11.1 =
factory_bot_rails 4.11.1 4.11.1 =
ffi 1.12.2 1.12.2 =
formatador 0.2.5 0.2.5 =
globalid 0.4.2 0.4.2 =
guard 2.15.1 2.15.1 =
guard-compat 1.2.1 1.2.1 =
guard-rspec 4.7.3 4.7.3 =
haml 4.0.7 4.0.7 =
haml-rails 1.0.0 1.0.0 =
hpricot 0.8.6 0.8.6 =
html2haml 2.2.0 2.2.0 =
i18n 0.9.5 1.5.1
interception 0.5 0.5 =
jquery-rails 4.4.0 4.4.0 =
json 2.5.1 2.5.1 =
kaminari 1.2.1 1.2.1 =
kaminari-actionview 1.2.1 1.2.1 =
kaminari-activerecord 1.2.1 1.2.1 =
kaminari-core 1.2.1 1.2.1 =
listen 3.0.8 3.0.8 =
loofah 2.8.0 2.8.0 =
lumberjack 1.0.13 1.0.13 =
mail 2.7.1 2.7.1 =
method_source 0.9.2 0.9.2 =
mini_mime 1.0.2 1.0.2 =
mini_portile2 2.4.0 2.4.0 =
minitest 5.14.2 5.14.2 =
nenv 0.3.0 0.3.0 =
net-ldap 0.17.0 0.17.0 =
nio4r 2.3.1 2.3.1 =
nokogiri 1.9.1 1.9.1 =
notiffany 0.1.3 0.1.3 =
orm_adapter 0.5.0 0.5.0 =
pg 0.20.0 0.20.0 =
power_assert 1.2.0 1.2.0 =
pry 0.12.2 0.12.2 =
pry-doc 1.1.0 1.1.0 =
pry-rails 0.3.9 0.3.9 =
pry-rescue 1.5.2 1.5.2 =
public_suffix 3.1.1 3.1.1 =
puma 5.1.1 5.1.1 =
rack 1.6.13 2.1.4
rack-cache 1.9.0 1.9.0 =
rack-test 0.6.3 0.6.3 =
rails 4.2.11.3 5.0.7.2
rails-controller-testing 1.0.5 +
rails-deprecated_sanitizer 1.0.3 -
rails-dom-testing 1.0.9 2.0.3
rails-erd 1.6.0 1.6.0 =
rails-html-sanitizer 1.3.0 1.3.0 =
railties 4.2.11.3 5.0.7.2
rake 13.0.3 13.0.3 =
rb-fsevent 0.10.4 0.10.4 =
rb-inotify 0.10.1 0.10.1 =
rb-readline 0.5.5 0.5.5 =
rdoc 6.2.0 6.2.0 =
redcarpet 3.5.1 3.5.1 =
responders 2.4.1 2.4.1 =
rspec 3.10.0 3.10.0 =
rspec-core 3.10.0 3.10.0 =
rspec-expectations 3.10.0 3.10.0 =
rspec-mocks 3.10.0 3.10.0 =
rspec-rails 4.0.1 4.0.1 =
rspec-support 3.10.0 3.10.0 =
ruby-graphviz 1.2.4 1.2.4 =
ruby_parser 3.15.0 3.15.0 =
sass 3.7.4 3.7.4 =
sass-listen 4.0.0 4.0.0 =
sass-rails 6.0.0 6.0.0 =
sassc 2.4.0 2.4.0 =
sassc-rails 2.1.2 2.1.2 =
sexp_processor 4.15.1 4.15.1 =
shellany 0.0.1 0.0.1 =
simplecov 0.17.1 0.17.1 =
simplecov-html 0.10.2 0.10.2 =
simplecov-rcov 0.2.3 0.2.3 =
spring 2.0.2 2.0.2 =
spring-commands-rspec 1.0.4 1.0.4 =
sprockets 3.7.2 3.7.2 =
sprockets-rails 3.2.2 3.2.2 =
test-unit 3.3.8 3.3.8 =

hkob.hatenablog.com