sprockets-rails
でNoMethodError
が発生したので原因の解説と対策を書いておきます。
発生するケース
以下の3つの条件が重なる場合に例外が発生します。
-
app.config.assets.quiet
がtrue
(デフォルト値) -
assets
を参照する - 例えば以下の様に開発環境は独自のloggerを使っており
ActiveSupport::Logger
ではなくLogger
クラスのインスタンスを設定している
config/development.rb
Rails.application.configure do
config.logger = Logger.new(STDOUT)
end
この状態でassetsを参照しているページにリクエストを行うと以下の様にNoMethodError
が発生します。
#<NoMethodError: undefined method `silence' for #<Logger:0x0000ffff792b3418 @level=0, @progname=nil, @default_formatter=#<Logger::Formatter:0x0000ffff792b2fb8 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x0000ffff792b29f0 @shift_period_suffix=nil, @shift_size=nil, @shift_age=nil, @filename=nil, @dev=#<IO:<STDOUT>>, @binmode=false, @mon_data=#<Monitor:0x0000ffff792b2950>, @mon_data_owner_object_id=8980>>
::Rails.logger.silence { @app.call(env) }
原因
config.logger
ではLogger
クラスのインスタンスを指定できますが、Logger
クラスのインスタンスにはsilence
メソッドが定義されていないためです。
そのためsprockets-rails
で例外が発生していました。
sprockets-rails/lib/sprockets/rails/quiet_assets.rb
def call(env)
if env['PATH_INFO'] =~ @assets_regex
::Rails.logger.silence { @app.call(env) }
else
@app.call(env)
end
end
対応
以下のいずれかの対応することで回避可能です。
1. config.logger
に指定する値はActiveSupport::Logger
のインスタンスに変更する
config/development.rb
Rails.application.configure do
- config.logger = Logger.new(STDOUT)
+ config.logger = ActiveSupport::Logger.new(STDOUT)
end
2. app.config.assets.quiet
をfalse
に設定する
config/development.rb
Rails.application.configure do
+ config.assets.quiet = false
config.logger = Logger.new(STDOUT)
end
FYI
このケースに遭遇してエラーが発生する場合にNoMethodError
ではなく独自の例外発生とエラーメッセージを出力する対応がされていました。
def raise_logger_silence_error
error = "You have enabled `config.assets.quiet`, but your `Rails.logger`\n"
error << "does not use the `LoggerSilence` module.\n\n"
error << "Please use a compatible logger such as `ActiveSupport::Logger`\n"
error << "to take advantage of quiet asset logging.\n\n"
raise LoggerSilenceError, error
end
当記事の投稿時点ではmaster
ブランチにはマージされていましたがこちらのコミットが含まれているリリースバージョンはまだリリースされていません。
環境
$ rails -v
Rails 7.0.4.3
$ bundle info sprockets-rails
* sprockets-rails (3.4.2)