CacheStore セッション削除で `options[:drop]` を正しく尊重するように修正

rails/rails

ActionDispatch::Session::CacheStore の delete_sessionoptions[:drop] を無視し、常に新しいセッション ID を生成していた問題を修正し、Rack のセッション削除契約に合わせて nil を返すようにしました。これにより、ドロップされたセッションが再割り当てされる不具合が解消されます。

背景

CacheStoredelete_session は、options[:drop] が指定されても常に generate_sid を呼び出し、新しいセッション ID を返していました。その結果、セッションが削除されるべき場面でクッキーが再生成され、意図しない再認証が行われていました。 (Rackdelete_session 契約では、options[:drop] が true のときは nil を返すことが求められます)。

CookieStore では同様のメソッドが正しく実装されており、options[:drop] が設定されている場合は generate_sid を呼び出さず nil を返しています。この不整合がテストで指摘され、CacheStore でも同等の挙動が必要となりました。\
\
この修正は、セッション管理の一貫性を保ち、期待通りにセッションを破棄できるようにするためのものです。

技術的な変更

CacheStore#delete_session に条件分岐を追加し、options[:drop] が true の場合は新しいセッション ID を生成せず nil を返すようにしました。変更前後のコードは以下の通りです。

変更前:

def delete_session(env, sid, options)
  @cache.delete(cache_key(sid.private_id))
  @cache.delete(cache_key(sid.public_id))
  generate_sid
end

変更後:

def delete_session(env, sid, options)
  @cache.delete(cache_key(sid.private_id))
  @cache.delete(cache_key(sid.public_id))
  generate_sid unless options[:drop]
end

このシンプルな条件分岐により、options[:drop] が指定されたときは nil が返り、Rack の期待通りにセッション書き込みがスキップされます。

さらに、テストが追加されて動作を検証しています。MemoryStore を使用して CacheStore を生成し、drop: true のケースで nil が返ること、drop が無い場合は新しいセッション ID が生成されることを assert_nilassert_not_nil で確認しています。

def test_delete_session_returns_nil_when_dropped
  cache = ActiveSupport::Cache::MemoryStore.new
  store = ActionDispatch::Session::CacheStore.new(->(env) { [200, {}, []] }, cache: cache)
  sid = Rack::Session::SessionId.new("0" * 32)

  # With options[:drop], delete_session must return nil so the session is
  # dropped rather than reassigned a fresh id (Rack's delete_session contract).
  assert_nil store.delete_session({}, sid, drop: true)

  # Without :drop, a fresh session id is returned.
  assert_not_nil store.delete_session({}, sid, {})
end

設計判断

この変更は CacheStore の実装を CookieStore と同等の振る舞いに揃えることを目的とし、既存の公開インターフェースを変更せずに内部ロジックだけを調整しています。generate_sid の呼び出しを条件付きにしただけなので、他のコードパスへの影響はなく、後方互換性が保たれます。

options[:drop] を正しく処理することで、セッションが意図的に破棄された際に不要なクッキーが再生成されることがなくなり、アプリケーション側で期待通りのセッションライフサイクル管理が可能になります。\
\
この設計は、Rack の仕様に忠実であることと、最小限の変更で既存機能を保全することという二つの観点でバランスが取れた判断と言えるでしょう。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
58e4c988

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文・背景・技術的な変更・設計判断が順序立てて記述され、結論的なまとめ(設計判断)が含まれているため構成は適切です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライトが正しい形式で記述され、PRリンクも # を含むリンク化が行われているため問題ありません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

エンジニア向けの専門的な内容で、余計な初心者向け解説がなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論→各論→結論の流れで構成され、段落はトピックセンテンスで始まり1段落1トピック、長さも適切です。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと完全に一致し、変更点が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語(CacheStore、delete_session、options[:drop]、generate_sid など)は PR と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的説明は PR の記述と合致し、因果関係も論理的に正しいです。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

全ての主張が PR のタイトル・説明・Diff で裏付けられており、余計な推測や矛盾はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR 番号 #57870 など数値・固有名詞は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルは PR タイトルの意味を日本語で適切に置き換えており、内容との食い違いはありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事内に PR に基づかない外部知識は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現のずれはなく、PR の記述と一致しています。