Active Record の定数を Ractor セーフにする修正

rails/rails

この PR は、Active Record と Arel が内部で保持している proc 定数ActiveSupport::Ractors.shareable_proc でラップし、Ractor 間で安全に共有できるようにします。挙動は変わらず、Ractor 未使用環境でも従来通りに動作します。

背景

Rails 7 以降で導入された Ractor は、オブジェクトの共有に厳格な制限を課します。そのため、プロシージャやラムダのような クロージャ が外部状態を捕捉しない限り、shareable_proc で包むことで安全に共有できます。Active Record の内部では、REJECT_ALL_BLANK_PROCBIND_BLOCK といった proc 定数 が複数箇所で利用されており、Ractor 環境での利用を阻害していました。これらの定数は外部状態を参照せず、引数だけで完結するため、Ractor セーフ化の対象として最適です。

技術的な変更

activerecord/lib/active_record/nested_attributes.rb では、REJECT_ALL_BLANK_PROCproc から ActiveSupport::Ractors.shareable_proc に置き換えられました。

@@ -300,7 +300,7 @@ module ClassMethods
-      REJECT_ALL_BLANK_PROC = proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }
+      REJECT_ALL_BLANK_PROC = ActiveSupport::Ractors.shareable_proc { |attributes| attributes.all? { |key, value| key == "_destroy" || value.blank? } }

activerecord/lib/arel/visitors/postgresql.rb では、バインド変数のフォーマットを行う BIND_BLOCK が同様にラップされました。

@@ -140,7 +140,7 @@ def visit_Arel_Nodes_IsDistinctFrom(o, collector)
-        BIND_BLOCK = proc { |i| "$#{i}" }
+        BIND_BLOCK = ActiveSupport::Ractors.shareable_proc { |i| "$#{i}" }
         private_constant :BIND_BLOCK

activerecord/lib/arel/visitors/to_sql.rb でも、プレースホルダー用の BIND_BLOCKshareable_proc に変更されています。

@@ -765,7 +765,7 @@ def visit_Arel_Attributes_Attribute(o, collector)
-        BIND_BLOCK = proc { "?" }
+        BIND_BLOCK = ActiveSupport::Ractors.shareable_proc { "?" }
         private_constant :BIND_BLOCK

これらの変更に伴い、bind_block メソッドは依然として同じ定数を返すだけで、呼び出し側のロジックは一切変わりません。プロシージャ自体が外部状態を捕捉しないため、shareable_proc に置き換えても機能上の差異はありません。

設計判断

PR では 既存定数をそのまま拡張 する方針が採用されました。新たに別名の定数や設定オプションを導入する代わりに、ActiveSupport::Ractors.shareable_proc でラップするだけの最小限の変更にとどめたことで、既存コードとの互換性が保たれます。さらに、private_constant が維持されるため、外部からの直接参照が制限された状態で安全に共有できます。これは、Ractor 対応を段階的に進める上で、リスクを抑えつつ API の破壊を避ける意図的なトレードオフと言えます。

まとめ

本変更は、Active Record と Arel が内部で使用する 3 つの proc 定数 を Ractor セーフにし、将来的なマルチスレッド/マルチプロセス実行環境への備えを整えました。動作上の変更はなく、既存アプリケーションへの影響もありません。Ractor 対応を進める上で、最小限の侵入性で安全性を確保した設計判断が示されています。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
05ec0b7d

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文、背景、技術的な変更、設計判断、まとめの全要素が揃っており、3部構成が明確です。

カスタムMarkdown構文 ⚠ WARNING

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

GitHubリンクが `[PR #57840](URL)` 形式ではなく `PR #57840` と記載されています。リンク記法は期待通りではありませんが、可読性への影響は少ないです。ファイル名付きハイライトは使用していないため問題ありません。

対象読者への適合性 ✓ PASS

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

専門的なエンジニア向けの技術的内容で、過度な初心者向け解説はありません。

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

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

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

Diff内容との照合 ✓ PASS

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

記事中の diff ブロックは提供された PR の diff と完全に一致しており、コード引用に誤りはありません。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`proc`、`shareable_proc`、`Ractor`、`private_constant` などの用語は PR と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

変更の目的・効果・互換性に関する説明は PR の記述と合致しています。

事実の突合 ✓ PASS

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

記事内の全ての主張は PR のタイトル・説明・diff に裏付けられており、捏造や推測は見当たりません。

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

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

PR 番号 #57840 や '3 つの proc 定数' など数値は正確です。

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

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

記事タイトルは PR タイトルと同義であり、一致しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース日程等の外部知識は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現に関する不一致はありません。