esm アジャイル事業部 開発者ブログ

永和システムマネジメントアジャイル事業部の開発者ブログです。

Rails5でミドルウェアの位置を変える

こんにちは、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 の起動時に例外が発生してしまうという問題があり、その対応としてこの変更があったようです。その影響により、削除して挿入しなおすというやり方ではミドルウェアの位置を変えられなくなりました。

手元では、一時的な対応としてミドルウェアを移動する操作を追加しました。

# 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 アプリのアップグレードを行なう際の参考になればと思います。