在Rails根目录之外的引擎中没有发生异常的stacktrace

时间:2018-10-02 16:17:47

标签: ruby-on-rails-5 rails-engines better-errors-gem

我正在处理升级到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

2 个答案:

答案 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消音器排除,后者会删除所有不是以libapp等开头。

解决方案是自己管理消音器,幸运的是,我们已经有一个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)/}