Ruby on Rails 6.0から6.1へのアップグレード
Posted by Kohei Hayashi on前回の記事ではRuby on Railsを5.2から6.0までのアップグレード方法を解説しましたが、今回の記事では6.0から6.1へのアップグレード方法を解説します。すでに6.0は通常のセキュリティーパッチ対象外となっているため、セキュリティー的には6.0までアップグレードしただけでは不十分で、6.1まで上げる必要があります。
GemfileでRailsバージョン更新
以下のようにGemfileを更新し、 bundle update
を実行し、新しいRailsをダウンロードします。
-gem 'rails', '~> 6.0.0'
+gem 'rails', '~> 6.1.0'
app:updateコマンドの実行
Rails6.0へのアップブレード記事で紹介したように、Railsバージョンアップグレードコマンドのrails app:update
を実行して設定ファイルの更新・追加を行います。追加、変更対象となるファイルは以下の通りです。
- bin/rails
- bin/rake
- bin/setup
- bin/spring
- bin/yarn
- config.ru
- config/application.rb
- config/boot.rb
- config/environment.rb
- config/environments/development.rb
- config/environments/production.rb
- config/environments/test.rb
- config/initializers/backtrace_silencers.rb
- config/initializers/filter_parameter_logging.rb
- config/initializers/new_framework_defaults_6_1.rb
- config/initializers/permissions_policy.rb
- config/puma.rb
- db/migrate/20220126080120_add_service_name_to_active_storage_blobs.active_storage.rb
- db/migrate/20220126080121_create_active_storage_variant_records.active_storage.rb
各ファイルごとにどのような処理を行なうかを尋ねられますので、新しいバージョンで上書き、既存バージョンをキープ、diff、マージなどを選択します。差分を見て、自身のカスタマイズがなければ上書き、あればマージツールを使って手動でマージ処理を行なう方法が良いかと思います。
ActiveRecord::Persistenceのupdate_attributesのupdateへの変更
ActiveRecord::Persistenceのupdate_attributesとupdate_attributes!メソッドは6.0へのアップグレードの段階で既にdeprecation対象となっていましたが、6.1では完全にコードベースから削除されました。もしまだ使っているようでしたら、それぞれupdate及びupdate!に変更します。
# Rails6.0
model.update_attributes params
model2.update_attributes! params
# Rails6.1
model.update params
model2.update! params
トランザクションブロック内でのreturn、break、throwのdeprecation
Rails6.1からは、ActiveRecord::Base.transactionブロック内でのreturn、break、throwがdeprecation対象となりました。
以前のバージョンでは以下のようなコードでトランザクション内でearly returnが出来ましたが、Rails6.1ではearly returnをトランザクションブロックの外に移すなどの工夫が必要になります。
# Rails 6.0
ActiveRecord::Base.transaction do
return if condition
# main logic
end
# Rails 6.1
return if condition
ActiveRecord::Base.transaction do
# main logic
end
form_withのリモートフォーム設定変更
Rails6.0以前ではform_withを使う場合はデフォルトでリモートフォームとなり、通常のフォームにしたい場合はlocal: true
の設定を追加していましたが、Rails6.1では通常フォームがデフォルトとなりました。(後述のconfig.action_view.form_with_generates_remote_forms = false
設定に該当)。そのため、もしリモートフォームを使っているviewがあった場合、明示的に設定するようにします。逆に通常フォームはlocal: true
の設定は不要となりますので、そのままでも害はありませんが外してしまっても良いでしょう。
# 6.1リモートフォーム
form_with model: model, local: false do |f|
# 6.1通常フォーム
form_with model: model do |f|
initializerを使った6.1デフォルト設定適用
通常のアップグレードでは、config/application.rbでconfig.load_defaults 6.0
のように、6.0のデフォルト設定を保持しつつ、config/initializers/new_framework_defaults_6_1.rbを使ってデフォルト設定を一つずつ上書きして動作を確認していくのですが、今回はいくつかの設定だとその方法がうまくいきませんでした。特にActiveRecordの設定は、デフォルト設定で一度設定するとActiveRecordクラスにその設定が記憶され、後の段階でinitializerでconfig設定を上書きしてもActiveRecordはその設定を再度読み込むことはしないので、6.1の設定で上書きしたと思っていても実は6.0のデフォルト設定で動いていることになり大変危険です。これはRailsフレームワークコードのバグですが、対処方法としてはconfig/initializers/new_framework_defaults_6_1.rbで上書きするのではなく、config/application.rbで以下のように直接上書きすることで防げます。
# config/application.rb
config.load_defaults 6.0
config.active_record.has_many_inversing = true
config.active_storage.track_variants = true
config.active_job.retry_jitter = 0.15
config.active_job.skip_after_callbacks_if_terminated = true
ActiveSupport.utc_to_local_returns_utc_offset_times = true
config.action_dispatch.ssl_default_redirect_status = 308
config.active_record.legacy_connection_handling = false
config.action_view.form_with_generates_remote_forms = false
config.active_storage.queues.analysis = nil
config.active_storage.queues.purge = nil
config.action_mailbox.queues.incineration = nil
config.action_mailbox.queues.routing = nil
config.action_mailer.deliver_later_queue_name = nil
config.action_view.preload_links_header = true
なお、以下の2つの設定についてはあえて上書き対象から外しています。この2つの設定は一度本番に適用してしまうと不可逆な変更なため、他の設定で本番運用を試してから適用した方が良いためです。
config.action_dispatch.cookies_same_site_protection = :lax
config.action_controller.urlsafe_csrf_tokens = true
ローカルとステージング環境で動作が問題なく、すべて自動テストがパスするようになったら本番にリリースし、問題が起こらないかしばらく観察します。
もし問題が起きた場合は6.0のコードにロールバックするか、バグ修正をすばやく行います。
特に問題がない場合は、以下のようにデフォルト設定を6.1に変更し、設定の上書きコードを全て削除して再度本番にリリースします。
# config/application.rb
config.load_defaults 6.1
これでRails6.1へのアップグレードは完了となります。
もしまだ6.0以前のバージョンで運用している方は、ぜひ参考にしてみてください。