対象読者
- 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アップグレード調査に少しでも役立つと嬉しいです。