ActionController::AllowBrowser のロード時に useragent を必須化
このPRは、ActionController::AllowBrowser がロードされるタイミングで useragent ライブラリを読み込むよう変更し、Eager Load 環境でも最初のリクエストでの遅延読み込みを防止します。
背景
Ractors の開発中に、最初のリクエスト時にのみ useragent が必要になることが判明しました。そのため、Eager Load 環境でも同様にリクエスト時に遅延して読み込まれるケースがありました。
現在の実装では、allow_browser のプライベートメソッドが実行されたときに require "useragent" が呼ばれ、リクエストごとに評価される可能性があります。この挙動は、モジュールがロードされた段階で依存を確定させるという Ruby の一般的な慣習から外れています。
技術的な変更
allow_browser のクラスメソッド定義直後に require "useragent" を追加し、プライベートメソッドからは削除 しました。これにより、モジュールがロードされた瞬間に一度だけ useragent が読み込まれます。
@@ -55,14 +55,14 @@ module ClassMethods
def allow_browser(versions:, block: -> { render file: Rails.root.join("public/406-unsupported-browser.html"), layout: false, status: :not_acceptable }, **options)
+ require "useragent"
before_action -> { allow_browser(versions: versions, block: block) }, **options
end
@@
private
def allow_browser(versions:, block:)
- require "useragent"
-
if BrowserBlocker.new(request, versions: versions).blocked?
ActiveSupport::Notifications.instrument("browser_block.action_controller", request: request, versions: versions) do
block.is_a?(Symbol) ? send(block) : instance_exec(&block)
この変更はファイル冒頭の require を追加するだけで、既存の API や呼び出し側コードに影響を与えません。
設計判断
モジュールロード時に依存ライブラリを必須化する 方針が採用されました。require "useragent" をクラスメソッドの先頭に置くことで、ロード順序を明示し、実行時の条件分岐を削減しています。プライベートメソッドからの削除は、重複した require 呼び出しを排除し、単一責任の原則に沿った整理です。
まとめ
ActionController::AllowBrowser のロード時に useragent が必須化されることで、Eager Load 環境でも確実に依存が解決され、リクエストサイクル中の遅延読み込みがなくなります。コード変更は最小限で、既存の挙動や設定への影響はありません。