ActiveRecord の readonly 属性を Ractor セーフに

rails/rails

ActiveRecord::Base の _attr_readonly がデフォルトで Ractor 共有可能 になるよう変更され、Ractor 環境でも安全に利用できるようになりました。

背景

Ractor 対応作業では、クラス属性として保持している 可変オブジェクト(Hash や Array)が複数スレッド間で共有できないことが障壁となります。ActiveRecord::Base._attr_readonly も同様に配列で保持されており、凍結されていないため Ractor 間でコピーが必要でした。以前に例外ラッパー設定を Ractor セーフにした作業(#57483)と同様のアプローチで、readonly 属性の共有可能化が行われました。

この変更により、属性追加時に配列を dup → freeze する代わりに、ActiveSupport::Ractors.make_shareable で共有可能オブジェクトに変換する方針が採られました。

技術的な変更

attr_readonly の実装変更

@@
-        self._attr_readonly |= attributes.map(&:to_s)
+        self._attr_readonly = ActiveSupport::Ractors.make_shareable(_attr_readonly | attributes.map(&:to_s))

_attr_readonly に属性を追加する際、従来の OR 演算子で配列を拡張 した処理を、ActiveSupport::Ractors.make_shareable でラップ した形に置き換えました。これにより、結果の配列は Ractor で安全に共有可能となります。

テスト補助の拡充

Ractor 共有可能性を検証するためのアサーションヘルパーが二つ追加されました。

@@
-          def assert_ractor_shareable(obj)
-            assert_nothing_raised { Ractor.make_shareable(obj) }
-          end
+          def assert_ractor_make_shareable(obj)
+            assert_nothing_raised { Ractor.make_shareable(obj) }
+          end
+
+          def assert_ractor_shareable(obj)
+            assert Ractor.shareable?(obj), "Expected #{obj.inspect} to be shareable, but it is not."
+          end

Ruby 4.0 以上では実際に Ractor.make_shareableRactor.shareable? を呼び出して検証し、古いバージョンではダミー実装が提供されます。

テストケースの追加

ActiveSupport::Testing::RactorsAssertionsBasicsTest にインクルードし、_attr_readonly が共有可能であることを確認するテストが追加されました。

@@
   include ActiveSupport::Testing::RactorsAssertions
@@
   def test_readonly_attributes_are_ractor_safe
     assert_ractor_shareable ReadonlyAuthorPost._attr_readonly
   end

また、バックトレースクリーナーのテストでも assert_ractor_make_shareable を使用するよう変更されています。

設計判断

変更点のスコープ

  • 属性追加時に共有可能化: 既存の attr_readonly 呼び出しコードはそのまま動作し、内部だけが Ractor 対応になるため、後方互換性が保たれます。
  • make_shareable のみ使用: 配列全体を凍結してから保存する従来の手法ではなく、ActiveSupport::Ractors.make_shareable に委譲することで、将来的に他の Ractor 共有ロジックと統一できます。

アサーションの二分化

assert_ractor_shareableassert_ractor_make_shareable を分けたのは、「既に共有可能か」「共有可能にできるか」 を明示的に区別する設計意図があるためです。これにより、テストが意図する検証内容が明確になります。

まとめ

_attr_readonlyActiveSupport::Ractors.make_shareable で包むことで、ActiveRecord の readonly 属性が Ractor 環境でも安全に共有できるようになりました。テスト支援も整備されたため、今後の変更が Ractor 互換性を損なうリスクが低減します。既存コードへの影響はなく、Rails の Ractor 対応がさらに前進したと言えるでしょう。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
1e8be075

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

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文・背景・技術的変更・設計判断・まとめの5部構成が明確で、総論→各論→結論の流れが保たれています。

カスタムMarkdown構文 ✓ PASS

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

コードブロックはすべて `言語:ファイルパス` 形式で正しく記述され、PR/Issue リンクは #番号 形式でリンク化されています。

対象読者への適合性 ✓ PASS

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

内容は Rails 開発者向けの専門的な記述であり、初心者向けの過剰な説明はありません。

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

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

各セクションは総論・各論・結論の段落で構成され、トピックセンテンスで始まり、1段落1トピック・6文未満で適切に区切られています。

Diff内容との照合 ✓ PASS

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

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

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`attr_readonly`、`Ractor`、`ActiveSupport::Ractors.make_shareable` などの用語は PR と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

変更の目的、実装手順、テスト追加の意図が PR の記述と合致し、技術的に正確です。

事実の突合 ✓ PASS

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

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

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

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

PR 番号やリンク先のコミット ID 等の数値は正確です。

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

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

記事タイトルは PR タイトル「Ractor safe readonly attributes」の日本語訳として適切です。

外部知識の正確性 ✓ PASS

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

Rails のバージョンサポート状況やリリース日程など、PR 外の外部知識は一切記載されていません。

時間表現の正確性 ✓ PASS

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

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