我正在处理升级到Rails 5.1的应用程序,当发生内部服务器错误时,我会收到异常消息,但没有堆栈跟踪。例如:
Completed 500 Internal Server Error in 25ms (ActiveRecord: 13.5ms)
NoMethodError - undefined method `performer' for #<AssignSiteToStudy::Form>
Did you mean? performer_id:
stdout或开发日志文件中没有其他信息。
经过一番调查,看来问题出在Better_errors gem中,特别是Rails.backtrace_cleaner.clean
删除了回溯的所有行:
# better_errors-2.5.0/lib/better_errors/middleware.rb:
def backtrace_frames
if defined?(Rails) && defined?(Rails.backtrace_cleaner)
Rails.backtrace_cleaner.clean @error_page.backtrace_frames.map(&:to_s)
else
@error_page.backtrace_frames
end
end
更新:实际错误发生在位于Rails根目录之外的引擎中。在Gemfile中使用path
进行引用,例如gem "my_engine", path: '~/dev/my_engine
。
答案 0 :(得分:0)
删除better_errors
gem可以解决此问题。现在我得到了:
Completed 500 Internal Server Error in 1674ms (ActiveRecord: 50.4ms)
undefined method `sites' for #<Class:0x000055a38ef961b8>
ActionView::Template::Error (undefined method `sites' for #<Class:0x000055a38ef961b8>):
1: $('#sites_panel').html('<%= escape_javascript render partial: ...
activerecord (5.1.6) lib/active_record/dynamic_matchers.rb:22:in `method_missing'
/home/user/dev/engine/app/services/update_site_assigned_to_study.rb:30:in `site'
etc.
etc.
之所以起作用,是因为Rails.backtrace_cleaner
过滤掉了所有行。这是因为Rails :: BacktraceCleaner中的过滤器和消音器的组合最终导致从引擎中删除发生错误的行,因为该行不在Rails根目录下。
通常,在这种情况下,当所有行都被回溯清除器ActionDispatch::DebugExceptions#log_error
过滤掉后,所有回溯都将显示为回退,而不显示任何内容。
但是,当使用better_errors
时,#log_error
中的常规Rails代码不会出现,而是会被调用。我推测better_errors
猴子会修补Rails。不管采用哪种方式,better_errors
都使用Rails.backtrace_cleaner
过滤掉所有行,而对于所有行都被过滤掉的情况,不会回退。
答案 1 :(得分:0)
这里的真正问题是错误来自Rails根以外的引擎。在Gemfile中,它被称为gem 'my_engine', path: '~/dev/my_engine'
。
这意味着删除Rails根并通常将/home/user/dev/project/app/...
转到app/...
的过滤器不会对Rails根之外的路径执行此操作,因此它们被Rails消音器排除,后者会删除所有不是以lib
,app
等开头。
解决方案是自己管理消音器,幸运的是,我们已经有一个ENV变量ENGINES_HOME,它指向引擎存储库的根目录。在initializers/backtrace_cleaner.rb
中:
Rails.backtrace_cleaner.remove_silencers!
if ENV['ENGINES_HOME']
Rails.backtrace_cleaner.add_filter { |line| line.sub(ENV['ENGINES_HOME'], "engines") }
end
Rails.backtrace_cleaner.add_silencer { |line| line !~ /^\/?(app|config|lib|spec|engines)/}