Arel を単体で require 可能にする変更
Arel を require "arel" しただけでは NameError が発生していましたが、active_support/ractors を先行ロードすることで単体でも正しく利用できるようになりました。
背景
Arel 単体での require が失敗する のは、Arel::Visitors::ToSql と Arel::Visitors::PostgreSQL がクラス定義時に ActiveSupport::Ractors を参照しているためです。実際に ruby -I activerecord/lib -e 'require "arel"' を実行すると、uninitialized constant Arel::Visitors::ToSql::ActiveSupport (NameError) がスローされます。この定数は Active Support の autoload に依存しているため、Active Record 経由で Arel がロードされる場合は問題になりませんが、Arel 単体でロードすると解決できませんでした。rails#57840 で報告された通り、arsi など SQL を直接検査するライブラリは Arel の単体ロードを前提としているため、上記の例外が実務に支障をきたしていました。
技術的な変更
activerecord/lib/arel.rb の先頭に require "active_support/ractors" を追加しました。これにより、Arel のロード時に必要な Ractors 関連定数が事前に定義され、NameError が回避されます。
@@ -1,5 +1,7 @@
# frozen_string_literal: true
+require "active_support/ractors"
+
require "arel/errors"
require "arel/crud"
変更は 2 行の追加のみで、既存のロジックには影響を与えていません。また、回帰テストとして activerecord/test/cases/arel/require_test.rb を新規追加し、Active Support を事前にロードせずに require "arel" が成功することを検証しています。
# frozen_string_literal: true
require_relative "helper"
module Arel
class RequireTest < Arel::Test
def test_arel_can_be_required_on_its_own
arel_load_path = $LOAD_PATH.find { |path| File.exist?(File.join(path, "arel.rb")) }
active_support_load_path = $LOAD_PATH.find { |path| File.exist?(File.join(path, "active_support/ractors.rb")) }
output = IO.popen(
[Gem.ruby, "-I", arel_load_path, "-I", active_support_load_path, "-e", 'require "arel"'],
err: [:child, :out],
&:read
)
assert_predicate $?, :success?, "Expected `require \"arel\"` to succeed on its own, but got:\n#{output}"
end
end
end
テストは新しいロードパスを指定して子プロセスで require "arel" を実行し、終了ステータスが成功であることを確認します。変更前はこのテストが失敗し、変更後は確実に成功することが確認されています。
設計判断
ActiveSupport の Ractors 機能を直接ロードする 方針が採用されました。Arel のクラス定義時に必要になる定数を確実に提供するため、条件分岐や遅延ロードを導入せずにシンプルに require "active_support/ractors" を追加しています。このアプローチは実装コストが最小であり、既存の Arel 使用者への互換性を保ちつつ、単体ロードの信頼性を向上させます。
唯一のトレードオフは Arel が ActiveSupport に依存する ことが明示的になる点です。Arel を純粋な独立ライブラリとして扱いたいケースでは、追加の依存が導入されますが、Rails エコシステム内での利用が前提であることを考慮すれば許容範囲と判断されています。代替案としては遅延ロードやモジュール分離が考えられましたが、実装の複雑化とテストカバレッジの維持が難しいため採用されませんでした。
まとめ
この PR は require "active_support/ractors" を追加し、Arel を単体で require した際の NameError を根本的に解消しました。新規テストにより回帰が防止され、SQL を直接解析する外部ライブラリでも安全に Arel を利用できるようになりました。