ActionableError のアクションハッシュがサブクラス間で共有されるバグを修正

rails/rails

ActionableErrorで定義したアクションがサブクラス間で漏れ出す問題を、コピーオンライト方式でハッシュを更新する実装に変更し、クラス継承時の状態汚染を防止しました。

背景

ActionableError.action が共有ハッシュを直接変更していた ため、サブクラスで定義したアクションが親クラスや兄弟クラスに漏れ、意図しないアクションが検出されていました。

_actionsclass_attribute としてデフォルト {} を持ち、サブクラスはデフォルトオブジェクトをそのまま継承するため、_actions[name] = block のインプレース更新が全クラスに反映されていました。

この状態はテスト subclass actions are not leaked to the parent or sibling subclasses で確認でき、修正前は "A""B" が親クラスにも漏れて失敗していました。

技術的な変更

action メソッドを不変なハッシュのマージに置き換えた ことで、毎回新しいハッシュが生成され、サブクラスごとに独立した状態が保たれます。

@@
-        _actions[name] = block
+        self._actions = _actions.merge(name => block)

self._actions = _actions.merge(name => block) は既存の継承ハッシュを基にマージを行うため、親クラスの定義はそのまま引き継がれつつ、変更は現在のクラスのみへ適用されます。

設計判断

コピーオンライト方式を採用することで、 class_attribute の他の再代入ロジック(例: StructuredEventSubscriber#debug_only 修正 #57676)と同様のパターンを維持し、状態共有による副作用を回避しました。

インプレースでハッシュを変更する (_actions[name] = block) アプローチはシンプルですが、クラス階層全体に影響を波及させる危険があるため、今回のようなライブラリ内部での拡張では不適切です。

この設計は不変性を尊重しつつ、サブクラス固有の設定を安全に追加できる点で、将来的な拡張や他の class_attribute 利用箇所にも適用しやすい利点があります。

まとめ

修正により ActionableError のサブクラスは自クラスで定義したアクションだけを保持し、親クラスや兄弟クラスへ漏れません。これで誤ったアクション検出や予期しないディスパッチが防止され、フレームワークの拡張性と安全性が向上しました。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
933ced00

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的な変更、設計判断(任意)、まとめの5つの要素が揃っており、総論→各論→結論の流れが保たれています。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックのファイル名付きシンタックスハイライトは正しい形式です。ただし、PRリンクの記法が `PR #57720` となっており、推奨の `[#57720](URL)` 形式と若干異なります。

対象読者への適合性 ✓ PASS

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

内容は Rails の内部実装に詳しいエンジニア向けで、初心者向けの過度な解説はありません。

パラグラフ・ライティング ⚠ WARNING

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

各セクションは総論パラグラフで始まり技術的説明が続いていますが、セクションごとの結論パラグラフが明示的に欠けています。セクション末尾に簡潔なまとめを入れるとさらに良くなります。

Diff内容との照合 ✓ PASS

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

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

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`class_attribute`、`copy-on-write`、`merge` などの用語は正しく使用されています。

説明の技術的正確性 ✓ PASS

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

技術的な説明は PR の問題点と修正内容に沿っており、矛盾や誤りは見当たりません。

事実の突合 ✓ PASS

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

記事の主張はすべて PR のタイトル、説明、Diff で裏付けられています。推測や捏造はありません。

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

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

PR 番号 #57720 だけが記載されており、正確です。他の数値・固有名詞の誤りはありません。

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

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

記事タイトルは PR の趣旨「ActionableError のサブクラス間でハッシュを共有しない」ことを適切に日本語化しています。

外部知識の正確性 ✓ PASS

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

バージョンや LTS など PR に無関係な外部知識は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現は使用されておらず、PR の記述と矛盾もありません。