config.load_defaultsとnew_framework_defaults_x_x.rbの関係を詳しく調べてみた
TL; DR(はじめに結論)
以下はRails 5.1から5.2にアップグレードしたケースを想定しています。
必要に応じてバージョン番号を読み替えてください。
- Rails 5.2アップグレード後に
config.load_defaults 5.2
と書くと、Rails 5.2のデフォルトの挙動になる - 一部にRails 5.1の挙動に戻したい項目があれば、
new_framework_defaults_5_2.rb
の該当項目のコメントを外し、そのうえで設定値を論理反転させる(true
はfalse
へ、false
はtrue
へ修正する) - Rails 5.1の挙動に戻す必要がなければ、
new_framework_defaults_5_2.rb
は削除しても構わない
はじめに
既存のRailsアプリを新しいバージョンにアップデートするために rails app:update
コマンドを使うと、 config/initializers
以下に new_framework_defaults_5_2.rb
のようなファイルが作成されます。
その一方で、config/application.rb
を見ると、config.load_defaults 5.1
のような設定も存在します。
Railsをアップデートしたときは、これら2つの設定ファイルをどのように使うのが良いのでしょうか?
僕自身、あまりしっかり理解しないまま使ってきてたので、詳しく調べてみました。
この記事で想定するRailsアプリケーション
この記事では以下のようなRailsアプリケーションを想定します。
- Rails 5.1の時代にrails newした
- その後、Rails 5.2にアップグレードした
- アップグレード時には
rails app:update
コマンドを使った(つまり、config/initializers/new_framework_defaults_5_2.rb
が作成された) -
config/application.rb
のconfig.load_defaults
は5.1
のまま
# ...
gem 'rails', '5.2.3'
# ...
# Be sure to restart your server when you modify this file.
#
# This file contains migration options to ease your Rails 5.2 upgrade.
#
# Once upgraded flip defaults one by one to migrate to the new default.
#
# Read the Guide for Upgrading Ruby on Rails for more info on each option.
# Make Active Record use stable #cache_key alongside new #cache_version method.
# This is needed for recyclable cache keys.
# Rails.application.config.active_record.cache_versioning = true
# Use AES-256-GCM authenticated encryption for encrypted cookies.
# Also, embed cookie expiry in signed or encrypted cookies for increased security.
#
# This option is not backwards compatible with earlier Rails versions.
# It's best enabled when your entire app is migrated and stable on 5.2.
#
# Existing cookies will be converted on read then written with the new scheme.
# Rails.application.config.action_dispatch.use_authenticated_cookie_encryption = true
# Use AES-256-GCM authenticated encryption as default cipher for encrypting messages
# instead of AES-256-CBC, when use_authenticated_message_encryption is set to true.
# Rails.application.config.active_support.use_authenticated_message_encryption = true
# Add default protection from forgery to ActionController::Base instead of in
# ApplicationController.
# Rails.application.config.action_controller.default_protect_from_forgery = true
# Store boolean values are in sqlite3 databases as 1 and 0 instead of 't' and
# 'f' after migrating old data.
# Rails.application.config.active_record.sqlite3.represent_boolean_as_integer = true
# Use SHA-1 instead of MD5 to generate non-sensitive digests, such as the ETag header.
# Rails.application.config.active_support.use_sha1_digests = true
# Make `form_with` generate id attributes for any generated HTML tags.
# Rails.application.config.action_view.form_with_generates_ids = true
module SampleApp
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.1
end
end
調査対象の設定値
この記事では Rails.application.config.action_view.form_with_generates_ids
に着目します。
この設定値は form_with
メソッドでフォームを作成した際に、各入力項目に id
属性を自動的に付与するかどうか決める設定値です。
<%= form_with(model: user, local: true) do |form| %>
<!-- ... -->
<%= form.text_field :email %>
<!-- ... -->
<% end %>
<form action="/users" ...>
<!-- ... -->
<input type="text" name="user[email]">
<!-- または -->
<input id="user_mail" type="text" name="user[email]">
<!-- ... -->
</form>
調査結果
config.load_defaults
と new_framework_defaults_5_2.rb
の form_with_generates_ids
の設定値の組み合わせによって、HTMLの出力内容がどうなるか調査したところ、次のような結果になりました。
load_defaults | 5.1 | 5.1 | 5.1 | 5.2 | 5.2 | 5.2 |
form_with_generates_ids | コメントアウト | true | false | コメントアウト | true | false |
id属性の有無 | 付かない | 付く | 付かない | 付く | 付く | 付かない |
わかったこと
上の結果からわかったことは以下のとおりです。
-
load_defaults
が5.1で、form_with_generates_ids
がコメントアウトされていると、Rails 5.1相当の挙動になる -
load_defaults
が5.2で、form_with_generates_ids
がコメントアウトされていると、Rails 5.2で導入された新しいデフォルトの挙動になる -
form_with_generates_ids
をtrue
またはfalse
にすると、load_defaults
の挙動を上書きすることができる
また、rails app:update
コマンドを実行して生成されるnew_framework_defaults_5_2.rb
は、「Rails 5.2のデフォルトの挙動にするための設定」がコメントアウトされています。
# trueにするとRails 5.2のデフォルトの挙動に一致する
# Rails.application.config.action_view.form_with_generates_ids = true
実際にはどう活用するのがよいか
では実際のアップグレード作業ではどのように活用するのがよいでしょうか?
理想的には次のような手順になると思います。
- Rails 5.2にアップグレードし、
rails app:update
コマンドを実行する -
load_defaults
は5.1
のままで、new_framework_defaults_5_2.rb
のコメントを1つずつ外し(つまり、Rails 5.2のデフォルトの挙動に変えて)、動作確認する -
new_framework_defaults_5_2.rb
のコメントを全部外しても問題が起きなければ、load_defaults
を5.2
に変更し、new_framework_defaults_5_2.rb
を削除する
module SampleApp
class Application < Rails::Application
# Rails 5.2のデフォルトの挙動で問題ないので5.1から5.2に変更
config.load_defaults 5.2
end
end
# 不要なので削除
新しいデフォルトの挙動では一部都合が悪い場合
一方、Rails 5.2のデフォルトの挙動では問題が起きる場合(たとえば、どうしてもid属性を自動的に付けたくない場合)は、次のような方法を取ることになるはずです。
-
load_defaults
を5.2
に変更する -
form_with_generates_ids
の設定値をtrue
ではなくfalse
にする(Rails 5.1相当の挙動にする) - その他の項目(Rails 5.2のデフォルトの挙動に変えても問題ない項目)については、
new_framework_defaults_5_2.rb
の設定をコメントアウト(または削除)する
module SampleApp
class Application < Rails::Application
# いったんすべてのデフォルトの挙動をRails 5.2相当にする
config.load_defaults 5.2
end
end
# 5.2のデフォルトの挙動では問題がある項目のみ、設定を上書きする
# (コメントを外すだけでなく、trueからfalse、またはfalseからtrueへ、というように、コメントを外す前の設定値を論理反転させる)
Rails.application.config.action_view.form_with_generates_ids = false
# 他の項目はRails 5.2のデフォルトでいいので削除
load_defaultsについてもう少し詳しく
過去のバージョンのデフォルト設定も同時に読み込まれる
load_defaults
で読み込んだデフォルト設定は、過去のRailsのバージョンのデフォルト設定も同時に読み込みます。
つまり、config.load_defaults 5.2
と書いた場合は、以下のようにRails 5.2だけでなく、5.1と5.0のデフォルト設定値も反映されます。
Rails 5.0のデフォルトの設定値を反映
↓
Rails 5.1のデフォルトの設定値を反映
↓
Rails 5.2のデフォルトの設定値を反映
なお、上で示したように、この仕組みが使われるのはRails 5.0までです。
load_defaults
メソッドの実装はそこまで複雑ではないので、詳細な仕様を理解したい場合はソースコードを直接読むのが良いと思います。
load_defaultsもnew_framework_defaults_x_xも指定しない場合はどうなるのか
config.load_defaults
もnew_framework_defaults_x_x
もどちらも何も指定しない場合は、どの設定値が使われるのか予想が付きません。
たとえば、form_with_generates_ids
はRails 5.1相当の挙動になりましたが、default_protect_from_forgery
はRails 5.2相当の挙動になりました。
このように、挙動の予想が付かなくなるので、load_defaults
には何らかの設定を入れておく方が良いでしょう。
module SampleApp
class Application < Rails::Application
# こういうことをしてはいけない!!(load_defaultsを指定しない場合は、挙動の予想が付かない)
# config.load_defaults 5.2
end
end