パラメータエンコーディングをデフォルトでRactorセーフにする

rails/rails

ActionController の parameter_encodings を Ractor 環境でも安全に共有できるようにし、既存挙動を保ちつつ内部実装を不変オブジェクトに置き換えました。

背景

この変更は ActionController::Base.parameter_encodings を Ractor で安全に扱えるようにすることを目的としています。Rails ではこのハッシュがアクションごとにパラメータのエンコーディングを保持し、未宣言のキーに対してはデフォルトプロックで自動生成していました。Ractor は共有オブジェクトのミュータブルな状態を許容しないため、ハッシュが凍結されているとデフォルトプロックが機能しなくなります。そこでハッシュ自体を不変にし、必要な更新は新しいハッシュを作成して置き換える方針としました。

技術的な変更

_parameter_encodings へのリーダー追加

モジュールに attr_reader :_parameter_encodings を導入し、テストから内部ハッシュを参照できるようにしました。リーダーは外部公開 API ではなくテスト専用で、既存の動作に影響を与えません。これにより shareability の検証が容易になります。

初期化処理の変更

setup_param_encode では @_parameter_encodingsActiveSupport::Ractors.make_shareable(Hash.new({})) で初期化します。空ハッシュを凍結かつ Ractor 共有可能にすることで、デフォルトプロックは不要となりハッシュは不変になります。結果としてハッシュへの直接ミューテーションが排除されます。

skip_parameter_encoding の実装

このメソッドは従来 @_parameter_encodings[action] = Hash.new { Encoding::ASCII_8BIT } の形でミューテートしていましたが、変更後は ActiveSupport::Ractors.make_shareable を使って新しいハッシュをマージし、再代入しています。具体的には Hash.new(Encoding::ASCII_8BIT) を作成し、対象アクションに紐付けた上で全体を shareable にします。ミューテーションが排除され、Ractor 間で安全に共有できます。

param_encoding の実装

個別パラメータのエンコーディング設定も同様に不変オブジェクトの置き換えで行います。引数を文字列に変換した後、対象アクションのハッシュを merge(param => encoding) で更新し、全体ハッシュを make_shareable で再構築します。これにより従来と同等の API を保ちつつ、内部データは常に凍結状態です。

テストの強化

テストファイルに ActiveSupport::Testing::RactorsAssertions を導入し、assert_ractor_shareable ParameterEncodingController._parameter_encodings で共有可能性を検証するケースを追加しました。従来のエンコーディング動作テストはそのまま残し、Ractor セーフティを新たに保証します。

設計判断

不変オブジェクトと make_shareable の組み合わせを採用したのは、Ractor が要求する共有オブジェクトの不変性を最小の侵入で満たすためです。ハッシュを凍結しつつ、必要な更新は新しいインスタンスを生成して置き換えることで、競合やデータ破壊のリスクを排除しました。これにより Rails 全体のスレッド/Ractor 安全性基準と合致します。

さらに公開 API(skip_parameter_encodingparam_encoding など)は変更せず、呼び出し側のコードはそのまま動作します。内部実装だけが immutable に変わるため、既存アプリケーションへの影響はありません。設計上のトレードオフは、ハッシュ生成のコストが若干増える点ですが、Ractor 環境での安全性向上という利益が上回ります。

まとめ

ActionController::Base.parameter_encodings を常に凍結かつ Ractor 共有可能な状態にし、ミューテーションを排除した実装に置き換えることで、Ractor 環境でも安全にパラメータエンコーディングを管理できるようになりました。API 互換性は維持され、テストにより shareability が保証されています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
14a001b2

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的な変更、設計判断(任意)、まとめの全てが揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックは使用されていませんが、GitHubリンクが「[PR #57848](URL)」という形式で記載されており、厳密な「[#57848](URL)」形式ではありません。その他の構文は問題ありません。

対象読者への適合性 ✓ PASS

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

エンジニア向けの高度な内容で、余計な初心者向け説明はなく、対象読者に適しています。

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

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

各セクション・各段落がトピックセンテンスで始まり、1段落1トピック、長さも適切で、空行で区切られています。

Diff内容との照合 ✓ PASS

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

記事中の変更点は Diff の内容と一致しており、コード例・テスト追加ともに正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Ractor、shareable、immutable などの用語が正しく使用され、PR の記述と整合しています。

説明の技術的正確性 ✓ PASS

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

技術的な説明は Diff と PR の記述に基づき、誤りや不整合はありません。

事実の突合 ✓ PASS

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

記事の主張はすべて PR のタイトル・説明・Diff で裏付けられており、推測や外部知識の付加はありません。

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

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

PR 番号 #57848 が正確に記載されています。その他数値的な誤りは見られません。

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

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

記事タイトルは PR の内容を正確に表現しており、一致しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース日程など、 PR に含まれない外部情報は記載されていません。

時間表現の正確性 ✓ PASS

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

時間表現の記載はなく、誤りもありません。