Ractor の shareability メソッドを Ruby 4.0 以降でのみ有効化
Ruby 3 系で Ractor.shareable_proc が未実装であることに起因する例外を防止するため、Rails は Ractor 関連ヘルパーを Ruby 4.0 以降でのみ有効にし、互換性のない環境では no‑op に置き換えます。
背景
Ractor.shareable_proc が Ruby 3.x に存在しないため、Rails の内部ヘルパーが呼び出すと NoMethodError が発生するリスクがあります。具体的には proc = ractor_shareable_proc { foo } として取得したプロックを ractor_make_shareable(Bar.new(proc)) に渡すと、Ruby 3.4 では例外がスローされます。これは make_shareable が未共有可能なプロックを受け取っても安全に動作しない という根本的な不整合です。
技術的な変更
この PR では activesupport/lib/active_support/ractors.rb に単一のバージョン判定を導入し、Ruby 4.0 以上でのみ本来の Ractor メソッドを呼び出す実装に切り替えました。条件分岐がシンプルになることで、コードベース全体に散在していたバージョンチェックが集中します。
変更前:
module ActiveSupport
module Ractors
class << self
if defined?(Ractor) && Ractor.respond_to?(:make_shareable)
def make_shareable(...)
Ractor.make_shareable(...)
end
else
def make_shareable(obj, copy: false)
obj
end
end
# shareable?, shareable_proc, shareable_lambda も同様の分岐
end
end
end
変更後:
module ActiveSupport
module Ractors
class << self
if defined?(Ractor) && RUBY_VERSION >= "4.0"
def make_shareable(...)
Ractor.make_shareable(...)
end
def shareable?(obj)
Ractor.shareable?(obj)
end
def shareable_proc(...)
Ractor.shareable_proc(...)
end
def shareable_lambda(...)
Ractor.shareable_lambda(...)
end
else
def make_shareable(obj, copy: false)
obj
end
def shareable?(obj)
obj
end
def shareable_proc(self: nil, &block)
block
end
def shareable_lambda(self: nil, &block)
block
end
end
end
end
end
Ruby 4.0 以上では Ractor.make_shareable などがそのまま呼び出され、Ruby 3.x ではすべてのヘルパーが引数をそのまま返す安全なスタブとなります。これにより、未実装メソッドへの呼び出しが原因で発生していた例外は完全に回避されます。
設計判断
バージョン依存ロジックを一箇所に集約し、Rails コア全体で散在していた個別チェックを排除した点が本変更の主たる設計方針です。ActiveSupport::Ractors 名前空間に閉じることで、Kernel への公開 API 追加による潜在的な衝突を回避し、将来的に Ruby 4.0 への移行が完了した際のクリーンアップも容易になります。
no‑op 実装は 後方互換性を担保しつつ、Ruby 3.x 環境での動作を安全に保ちます。これにより、Rails アプリケーションは Ruby のバージョンに応じて自動的に適切な挙動を選択でき、追加のバージョンチェックコードを書き加える必要がなくなります。
まとめ
本 PR は Ractor の shareability ヘルパーを Ruby 4.0 以降でのみ有効化し、Ruby 3.x では安全な no‑op に置き換えることで、未実装メソッド呼び出しによる例外を根本的に排除しました。バージョン判定を ActiveSupport::Ractors に集中させた設計により、コードの可読性と保守性が向上しています。