Ответ 1
Проблема заключается в том, что консоль IRB реализует собственный шумоглушитель Backtrace, который отличается от Rails. Но он может быть переопределен IRB.
Из исходного кода IRB видно, что глушитель который вызывается здесь, используя метод filter_backtrace
из класс WorkSpace. Таким образом, мы можем исправить этот метод, чтобы использовать глушитель Rails поверх IRB по умолчанию.
Патч может быть помещен в инициализатор 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
Как прокомментировано в коде, нам нужно иметь дело с одной небольшой проблемой - глушитель Rails работает на всей backtrace (передается как массив строк), тогда как метод блокировки 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
Тест (с глушителем Rails по умолчанию)
$ rails c
Loading development environment (Rails 4.2.5.1)
>> 1/0
ZeroDivisionError: divided by 0
>>
Пример с исключением, вызванным внутри метода модели:
$ 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'
>>
Как видно, Rails внутренние строки stttrace отключены, а корневые пути Rails отфильтровываются.