RailsのセッションCookieが「session_id」から切り替わらなかった理由と対処法
_swipe_app_session が付かなかった事件
Rails 8 + API モードのプロジェクトで、config/initializers/session_store.rb に
Rails.application.config.session_store :cookie_store,
key: "_swipe_app_session",
secure: true,
httponly: true
のようなカスタム設定を書いたのに、ブラウザにはいつまで経っても _session_id が届いてしまう――そんな現象に遭遇しました。設定を何度見直しても正しそうなのに、結果が変わらない。原因は「ミドルウェアを差し込むタイミング」にありました。
初期化の順番とサンプルコードで俯瞰
まずは「普通に書くとどうなるか」を簡単な例で追いかけてみましょう。
# config/application.rb
module DemoApp
class Application < Rails::Application
config.load_defaults 8.0
config.api_only = true
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
end
end
# config/initializers/session_store.rb
Rails.application.config.session_store :cookie_store, key: "key_name"
どちらも素直に見えますが、実際には次の順番で処理されています。
-
application.rbがクラス定義として評価される
→config.middleware.use ...が その場で実行され、CookieStore が「デフォルト設定」のまま登録される。 -
Rails.application.initialize!が呼ばれ、初期化フェーズに突入する。 - そこでようやく
config/initializers/session_store.rbが実行され、config.session_store(=config.session_options)が書き換わる。
しかし肝心のミドルウェアは すでに登録済み。あとから変更された config.session_options は既にスタックに積まれている CookieStore には反映されません。そのためブラウザには旧来の _session_id が飛び続ける、というわけです。
解決策と「初期化」+「ミドルウェア」の理解
どう直したか
ミドルウェアを挿し込むタイミングを「初期化が完了した後」にずらして、改めて登録し直します。
# config/application.rb
module SwipeApp
class Application < Rails::Application
config.load_defaults 8.0
config.api_only = true
config.middleware.use ActionDispatch::Cookies
initializer "session_store.configure" do |app|
app.middleware.use ActionDispatch::Session::CookieStore, app.config.session_options
end
end
end
initializer ブロックは config/initializers/*.rb と同じタイミングで実行されるため、その時点では session_store.rb による設定が app.config.session_options に入っています。これを渡してから CookieStore を登録すれば、_swipe_app_session というキー名を含め、意図した Secure/SameSite/Domain の設定も丸ごと反映されます。
初期化とは?ミドルウェアとは?
-
初期化 … アプリがリクエストを受け付ける前に一度だけ行うセットアップ。Rails では
config/application.rb→config/environments/*.rb→config/initializers/*.rbの順で読み込まれます。 -
Rack ミドルウェア … リクエスト・レスポンスを通過させながら処理を差し込む仕組み。
ActionDispatch::CookiesやActionDispatch::Session::CookieStoreなどがここに属します。
今回の問題は「クラス定義の段階(初期化より前)でミドルウェアが登録されてしまった」こと。つまり設定ファイルは正しかったのに、適用するタイミングがズレていただけだったのです。
まとめ
-
_swipe_app_sessionが付かなかったのは、CookieStore を 初期化前に 登録していたせいでconfig.session_optionsが空のまま渡っていたから。 -
initializerブロックでミドルウェアを差し込むように変更すると、session_store.rbの設定が反映された状態で_swipe_app_sessionが発行される。 - Rack ミドルウェアは「登録した時点のオプション」で固定されるため、設定を後から変える場合は登録タイミングも意識する。
Rails の初期化については、サーバー起動してくれるまでにどのようなファイルがどんな順序で実行されるのかを知ることで、起動できないといったエラーや今回の僕のような標準設定が意図しない形で使用されてしまうというミスを防ぐことができると思いますので覚えておくといいのかなと思いました。
Discussion