こんにちは、hibariya です。先日から、自分のかかわっている Rails アプリを 5.0.0 にアップグレードしています。そのときに意外な箇所でつまずいたことを書きたいと思います。なお、全体的なアップグレードについては公式の A Guide for Upgrading Ruby on Rails や、Release Notes、willnet さんの スライド が参考になります。
そのプロジェクトでは、理由あっていくつかのミドルウェアを Rails::Rack::Logger より手前にもってくる必要があります。アップグレードする前の 4.2 では次のような操作をすればミドルウェアの位置を変えられました。
# config/application.rb # 中略... config.middleware.delete ActionDispatch::Cookies config.middleware.insert_before Rails::Rack::Logger, ActionDispatch::Cookies # 中略...
ところが 5.0.0 ではある理由によりミドルウェアの削除操作が最後にまとめて実行されるようになりました。そのため、上記の操作は見た目どおりに読めば「ミドルウェアAを削除してBの手前に挿入」ですが、5.0.0 では「ミドルウェアAをBの手前に挿入して、最後にスタックの中のミドルウェアAをすべて削除」という意味になります。
経緯としては、Rails は Rack::Runtime がスタックに存在することを想定しているため、アプリケーション側で Rack::Runtime を削除すると Rails の起動時に例外が発生してしまうという問題があり、その対応としてこの変更があったようです。その影響により、削除して挿入しなおすというやり方ではミドルウェアの位置を変えられなくなりました。
- Rack::Runtime can only be disabled in an initializer
- unable to re-insert middleware that was previously deleted with middleware.delete
手元では、一時的な対応としてミドルウェアを移動する操作を追加しました。
# config/application.rb # 中略... module MyRailsApp module MiddlewareStackProxyExtension refine Rails::Configuration::MiddlewareStackProxy do def move_before(dest, src) operations << [:delete, [src], nil] << [:insert_before, [dest, src], nil] end end end class Application < Rails::Application using MiddlewareStackProxyExtension config.middleware.move_before Rails::Rack::Logger, ActionDispatch::Cookies config.middleware.move_before Rails::Rack::Logger, ActionDispatch::Session::CookieStore # 中略... end end
この変更についての記述はあまり目立たないこともあり、私は気付くのに少し時間がかかりました。ミドルウェアの位置を変えるような Rails アプリのアップグレードを行なう際の参考になればと思います。