AttributeMethods を Ractor セーフにするための凍結化と初期化変更
この PR は AttributeMethods.aliases_by_attribute_name、.attribute_aliases、.attribute_method_patterns を Ractor 間で安全に共有できるよう、デフォルト値を凍結し継承時に初期化する変更を導入します。従来の遅延初期化と可変オブジェクトに伴う共有リスクを排除し、振る舞いを保ったままマルチスレッド実行環境への適合性を高めます。
背景
AttributeMethods の内部キャッシュである aliases_by_attribute_name、attribute_aliases、attribute_method_patterns はデフォルトで可変なハッシュや配列を保持しており、Ractor に渡すと共有不可能になる問題がありました。Ractor 安全性を求める Rails コアでは、これらのデータ構造を凍結し、遅延評価を排除して早期に安全な状態で設定する方針が取られました。テストでも assert_ractor_shareable が失敗していたことが変更の直接的な動機です。
技術的な変更
EMPTY_HASH を Hash.new([].freeze).freeze として定義し、@aliases_by_attribute_name の初期値に使用することで、デフォルトの空ハッシュ自体が共有可能な状態になります。
EMPTY_HASH = Hash.new([].freeze).freeze # :nodoc:
attribute_aliases と attribute_method_patterns の class_attribute 定義に freeze を付与し、デフォルトオブジェクトが変更不可になるようにしました。また、@aliases_by_attribute_name を継承時に EMPTY_HASH で初期化し、遅延評価用の default_proc を廃止しています。
class_attribute :attribute_aliases, instance_writer: false, default: {}.freeze
@aliases_by_attribute_name = EMPTY_HASH
class_attribute :attribute_method_patterns, instance_writer: false, default: [ClassMethods::AttributeMethodPattern.new].freeze
各属性メソッドの追加ロジック(attribute_method_prefix、attribute_method_suffix、attribute_method_affix)は、配列操作後に結果を freeze して再代入する形に変更され、可変配列が残らないようにしました。
prefixes.map! { |prefix| AttributeMethodPattern.new(prefix: prefix, parameters: parameters) }
self.attribute_method_patterns = (attribute_method_patterns + prefixes).freeze
テストコードは ActiveSupport::Testing::RactorsAssertions をインクルードし、assert_ractor_shareable で新しいデータ構造が Ractor で共有可能であることを検証しています。
require "active_support/testing/ractors_assertions"
...
include ActiveSupport::Testing::RactorsAssertions
...
assert_ractor_shareable model.aliases_by_attribute_name
assert_ractor_shareable model.attribute_aliases
assert_ractor_shareable model.attribute_method_patterns
ActiveRecord のテストでも、attribute_method_patterns のリセット処理が attribute_method_patterns = @old_matchers とシンプルに置き換えられ、同様に凍結された配列を再代入しています。
設計判断
AttributeMethods の公開 API を変更せずに、内部キャッシュを凍結オブジェクトへ置き換える方針が採用されました。新しい設定キーやメソッドは導入せず、既存の attribute_method_patterns 配列をそのまま凍結して再代入することで、後方互換性を保ちつつ Ractor 共有可能にしました。遅延初期化を継承時に前倒しした点は、Ractor 境界での不変性を保証するための最小限の侵入的変更です。
まとめ
本変更により、aliases_by_attribute_name、attribute_aliases、attribute_method_patterns がデフォルトで凍結され、Ractor 間で安全に共有できるようになりました。振る舞いは従来と変わらず、シングルスレッド環境でも同様に動作しますが、マルチスレッド/Ractor 環境での安全性が向上し、将来的な並行実行の拡張基盤が整備されました。