在Rails控制台中使用BacktraceCleaner?

use*_*110 11 ruby-on-rails ruby-on-rails-4

我在调试模式下使用Rails控制台非常多,而且只需要更改控制台窗口的大小就有点乏味,这样我就可以找到列表顶部而无需滚动.

我认为BacktraceCleaner可以帮助解决这个问题,但我无法让它在控制台中保持沉默.

我把这段代码放在我的应用程序的初始化器中.

bc = Rails.backtrace_cleaner
bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
bc.add_silencer { |line| line =~ /console.rb/ }
bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
bc.add_silencer { |line| line =~ /rdebug-ide/ }
Run Code Online (Sandbox Code Playgroud)

但对控制台错误没有影响.所以我直接在控制台中尝试了它:

>>bc = Rails.backtrace_cleaner
>>bc.add_silencer { |line| line =~ /console.rb/ }
>> 1/0
   ZeroDivisionError: divided by 0
from (irb):23:in `/'
from (irb):23
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands /console.rb:90:in `start'
from C:/Ruby193/lib/ruby/gems/1.9.1/gems/railties-4.0.3/lib/rails/commands/console.rb:9:in `start'
Run Code Online (Sandbox Code Playgroud)

- 仍然看到包含'console.rb'的回溯线.Rails.backtrace_cleaner是否返回了一些不是Rails控制台环境中使用的清理程序?

如何在控制台回溯中获得(或安装)回溯清理器的句柄?

Bor*_*aMa 4

问题在于 IRB 控制台实现了自己的硬连线回溯消音器,该消音器与 Rails 的消音器不同。但它可以通过猴子修补 IRB 来覆盖

从IRB的源代码中我们可以看到,这里使用WorkSpace类filter_backtrace中的方法调用消音器。因此,我们可以修补此方法,以在默认 IRB 的基础上使用 Rails 消音器。

该补丁可以放入 Rails 初始化程序中,但我认为更简洁的方法是使用IRB_RC可以设置为任何 ruby​​ 代码并在 IRB 初始化期间调用的配置变量。因此,我们将仅将补丁保留在 IRB 的上下文中,并且不会影响 Rails 应用程序代码本身。

以下代码转到~/.irbrc

if ENV['RAILS_ENV']

  # silence console backtraces using BacktraceSilencer from Rails
  IRB.conf[:IRB_RC] = Proc.new do

    class IRB::WorkSpace
      alias_method :orig_filter_backtrace, :filter_backtrace

      def filter_backtrace(bt)
        filtered_bt = orig_filter_backtrace(bt)

        # The Rails silencer operates on the whole backtrace therefore
        # we need to temporarily convert the particular trace line to an array
        rails_backtrace_cleaner.clean(Array(filtered_bt)).first
      end

      private

      def rails_backtrace_cleaner
        Rails.backtrace_cleaner
      end

    end
  end
end
Run Code Online (Sandbox Code Playgroud)

正如代码中所注释的,我们需要处理一个小问题 - Rails 消音器对整个回溯进行操作(作为行数组传递),而 IRB 的消音方法是为每一行单独调用的。这就是为什么该行在传递到 Rails 消音器之前会暂时转换为数组的原因。

如果您确实想要一个自定义消音器,而不是 Rails 消音器,请使用类似以下的内容:

  def rails_backtrace_cleaner                                  
    @rails_backtrace_cleaner ||= begin
      bc = ActiveSupport::BacktraceCleaner.new
      bc.add_filter { |line| line.gsub(Rails.root.to_s, '<root>') }
      bc.add_silencer { |line| line.index('<root>').nil? and line.index('/') == 0 }
      bc.add_silencer { |line| line.index('<root>/vendor/') == 0 }
      bc.add_silencer { |line| line =~ /console.rb/ }
      bc.add_silencer { |line| line =~ /ruby-debug.ide.rb/ }
      bc.add_silencer { |line| line =~ /rdebug-ide/ }
      bc
    end
  end
Run Code Online (Sandbox Code Playgroud)

测试(使用默认的 Rails 消音器)

$ rails c
Loading development environment (Rails 4.2.5.1)
>> 1/0
ZeroDivisionError: divided by 0    
>>
Run Code Online (Sandbox Code Playgroud)

模型方法内引发异常的示例:

$ rails c
Loading development environment (Rails 4.2.5.1)
>> BaseUser.find(1234).update_rating
RuntimeError: Exception occured!
  from app/models/base_user.rb:51:in `update_rating'
>> 
Run Code Online (Sandbox Code Playgroud)

可以看出,Rails 内部堆栈跟踪行被静音,并且 Rails 根路径被过滤掉。