対象読者
- Railsをアップグレードしていて
config.action_dispatch.return_only_request_media_type_on_content_typeって何?となった人 - Rails 7.0 から Rails 7.1 へアップグレードするにあたって
ActionDispatch::Request#content_typeの挙動が変わって困っている人 - Rails 7.0 以降での
ActionDispatch::Request#content_typeの実装が知りたい人
なお、新旧の ActionDispatch::Request#content_type の定義箇所については記載していますが、細かい挙動の差異については、この記事では紹介していません。
config.action_dispatch.return_only_request_media_type_on_content_type とは?
Rails 7.0 から、デフォルトでは ActionDispatch::Request#content_type が Content-Type ヘッダをそのまま返すようになっています。
詳しくは上記ガイドを参照してほしいのですが、Rails 7.0 より前とあとでは ActionDispatch::Request#content_type の挙動が大きく違います。
従来の挙動を維持したい場合は config.action_dispatch.return_only_request_media_type_on_content_type = true とすればよいのですが、Rails 7.1 でこの設定が意味をなさなくなり、対応が必要になってきます。
どうすればよいか
に書いてある通りなのですが、 ActionDispatch::Request#media_type を ActionDispatch::Request#content_type の代わりに利用してください。
Rails 7.0 までで、必要に応じて ActionDispatch::Request#content_type 利用箇所を ActionDispatch::Request#media_type に置き換え、 config.action_dispatch.return_only_request_media_type_on_content_type を削除しても問題なく動作するかを確認すると良いはずです。
ActionDispatch::Request#content_type の変更履歴
頑張って調べてみました。
Rails 7.0 より前
Rails 7.0 より前の ActionDispatch::Request#content_type は ActionDispatch::Http::MimeNegotiation#content_type として、
で定義されていました。
ActionDispatch::Http::MimeNegotiation を ActionDispatch::Request で include し、 ActionDispatch::Request#content_type として呼び出せるようになっていた、ということです。
Rails 7.0
しかし Rails 7.0 からは、以下のように config.action_dispatch.return_only_request_media_type_on_content_type オプションで条件分岐するようになっています。
この条件分岐で、デフォルトでは super の content_type を呼ぶようになっています。
Rails 7.1 から
Rails 7.1 からは、Rails 7.0 において存在していた条件分岐が消え、 ActionDispatch::Http::MimeNegotiation#content_type も消え、 config.action_dispatch.return_only_request_media_type_on_content_type 設定を使うと警告が出るようになっています。
Rails 7.1.5.1 時点のコードを見ても、 ActionDispatch::Http::MimeNegotiation#content_type が存在していないことを確認できるはずです。
Rails 7.2 から
Rails 7.2 からは、 config.action_dispatch.return_only_request_media_type_on_content_type を設定しようとする警告すら消え、 ActionDispatch::Request#content_type の変更の移行期間が終了しています。
Rails 7.2.2.1 時点のコードを見ても、 config.action_dispatch.return_only_request_media_type_on_content_type にまつわるコードが完全に無くなっていることを確認できるはずです。
新しい ActionDispatch::Request#content_type の定義を探してみる
上でも書いたとおり、 Rails 7.0 からは、デフォルトでは super の content_type を呼ぶようになっています。
この super の content_type がどこで定義されているのかモヤモヤする方もいると思うので、解説します。
Rails 7.1 において、 ActionDispatch::Request では、以下のように各種 module が include されています。
この何処かで ActionDispatch::Request#content_type の実体が定義されているはずですが、調べるのが面倒なので Rails 7.1 の環境を用意し、 ActionDispatch::Request#content_type の実体がどこで定義されているかを確認してみます。
local 環境に直で rails new して Rails 7.1 の環境を用意すると、local 環境が汚れてしまうので、
の image をお借りして確認します。
$ docker run -it bitnami/rails:7.1.3 bash
root@737436f37791:/app# rails -v
Rails 7.1.3.2
root@737436f37791:/app# rails new hoge
root@737436f37791:/app# cd hoge/
root@737436f37791:/app/hoge# rails c
Loading development environment (Rails 7.1.5.1)
irb(main):001> ActionDispatch::Request.new({}).method(:content_type).source_location
=> ["/opt/bitnami/ruby/lib/ruby/gems/3.2.0/gems/rack-3.1.8/lib/rack/request.rb", 308]
どうやら rack で定義されているものを利用しているようです。
rackのバージョンは若干違うかもしれませんが、コードを確認してみると、たしかにその辺りに content_type メソッドがあります。
Rack::Request::Helpers module で定義されたこの content_type メソッド が、 Rails 側の
で include Rack::Request::Helpers され、 ActionDispatch::Request#content_type が呼び出し可能になっている、というわけです。
つまり、Rails 7.0 からは、 rack の実装を利用するようになった、ということですね。
まとめ
ここまでをざっくりまとめると
- Rails 7.0 から
ActionDispatch::Request#content_typeの挙動が変わる-
config.action_dispatch.return_only_request_media_type_on_content_typeフラグで設定可能だが、Rails 7.1 から完全に挙動が変わる -
ActionDispatch::Request#media_typeをActionDispatch::Request#content_typeの代わりに利用すればよい
-
- Rails 7.0 より前の
ActionDispatch::Request#content_typeはActionDispatch::Http::MimeNegotiation#content_typeで定義されている - Rails 7.0 からの
ActionDispatch::Request#content_typeはRack::Request::Helpers#content_typeで定義されている
ということになります。
ここまでご覧いただきありがとうございました。
この記事が、あなたのRailsアップグレード調査に少しでも役立つと嬉しいです。