Active Record のスコープを Ractor 共有可能に

rails/rails

Active Record の scope メソッドが Ractor 環境で安全に使用できるよう、共有可能な Proc に変換する変更が加えられました。これにより、マルチスレッド・マルチプロセス構成でスコープロジックをそのまま利用できます。

背景

これまで Ractor 上で Active Record のスコープを呼び出すと、スコープ本体が保持する Proc が共有不可能となり Ractor::IsolationError が発生していました。スコープはモデルクラスのクエリロジックを再利用する重要な手段であり、Ractor の導入が進む Rails アプリケーションでの利用が阻害されていました。したがって、スコープ定義を Ractor でも安全に扱えるようにする必要がありました。

この問題への対処として、Rails コアチームは ActiveSupport::Ractors.try_shareable_proc を利用し、Proc を Ractor 共有可能な形に変換するアプローチを採用しました。変更は ActiveRecord::Scoping::Named モジュールの scope メソッド内部に限定され、既存の API 仕様は一切変更されません。テストも追加され、Ractor 環境での正しい動作が検証されています。

技術的な変更

scope メソッドでは、拡張モジュールを生成する部分を Module.new(&block).freeze に置き換え、生成されたモジュールを不変にしました。これは Ractor がオブジェクトの共有に対して不変性を要求するための前提条件です。続いて、スコープ本体が Proc である場合は ActiveSupport::Ractors.try_shareable_proc(&body) を呼び出し、共有可能な Proc (scope_body) を取得しています。取得した scope_body_exec_scope に渡され、従来と同様の動作を保ちつつ Ractor 互換性が確保されています。

スコープの実装は、proc do |*args| ... end というラッパー Proc に包まれ、最終的に ActiveSupport::Ractors.try_shareable_proc(&scope_method) で再度共有可能化されます。その結果、singleton_class.define_method(name, &scope_method) によりクラスメソッドとして登録されます。従来の define_method にブロックを直接渡す形から変更はなく、内部ロジックだけが Ractor 対応に変わっています。

テストコード activerecord/test/cases/scoping/named_scoping_test.rb では、共有可能な Proc で定義したスコープが例外なしで呼び出せること、そして共有不可能な Proc が Ractor 環境で使用された際に Ractor::IsolationError が発生することを確認しています。テストは ActiveSupport::Ractors.with(unshareable_proc_action: :raise) コンテキスト内で実行され、期待通りの例外挙動を検証しています。これにより、実装の正当性が自動テストで保証されています。

設計判断

ActiveSupport::Ractors.try_shareable_proc を利用して Proc をラップする方針は、既存の scope API を維持しつつ Ractor 互換性を提供する最小侵襲の設計です。新たに別名の設定やオプションを導入せず、内部でのみ Proc の変換を行うことで、利用者側のコード変更は不要です。さらに、モジュールの freeze により不変オブジェクトとして安全に共有できる点が設計上の重要ポイントです。

この実装は、Ractor が要求するオブジェクトの不変性と共有可能性を尊重しながら、Active Record のスコープ機能をそのまま活かすことを可能にします。非共有可能な Proc が使用された場合は、意図的に例外を発生させて早期に問題を検出できるため、開発者にとっても安全性が向上します。結果として、Ractor を活用したアプリケーションでも従来通りのスコープ記法が利用できるようになりました。

まとめ

この PR では、Active Record の scope メソッドが Ractor 環境でも安全に動作するよう、Proc を共有可能化しモジュールを freeze する変更が加えられました。既存の API を保持しつつ、テストで挙動を裏付けているため、導入時のリグレッションリスクは低くなっています。今後、Ractor を活用した Rails アプリケーションでスコープをそのまま利用できることが期待されます。

記事メタデータ

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

この記事は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 #57927](URL)" となっており、要求される形式 "[#57927](URL)" とは異なる。コードブロックは存在しないためファイル名付きシンタックスハイライトのチェックは対象外。

対象読者への適合性 ✓ PASS

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

内容はRailsエンジニア向けで、専門用語が適切に使用されており、過度な初心者向け説明はない。

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

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

技術的な変更セクションの段落が10文と長すぎる。6文以上の段落は分割すべきであるが、他の段落はトピックセンテンスで始まり構成も適切。

Diff内容との照合 ⚠ WARNING

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

記事内にコードブロックが無いため Diff 内容との直接照合はできない。記述は Diff の変更点と概ね合致しているが、コード例が抜けている点は改善余地。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

Ractor、Proc、freeze、ActiveSupport::Ractors.try_shareable_proc などの用語が正しく使用されている。

説明の技術的正確性 ✓ PASS

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

技術的主張は PR の Diff と一致し、因果関係も論理的に説明されている。

事実の突合 ✓ PASS

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

すべての主張が PR のタイトル、説明、Diff、テストコードで裏付けられている。外部知識の付加はなし。

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

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

PR番号 #57927 が正確に記載されている。その他数値・固有名詞の誤りはない。

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

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

記事タイトルは PR の内容「Make Active Record scope methods Ractor‑shareable」を日本語で正確に表現している。

外部知識の正確性 ✓ PASS

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

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

時間表現の正確性 ✓ PASS

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

時間表現は使用されておらず、PR の記述と整合性の問題はない。