Возьмем пример
class E < StandardError; end
begin
raise E
rescue E
puts "here we rescue E"
rescue
puts "here we rescue StandardError"
end
Если вы используете вот такой вот каскадный rescue
, то вы наверняка знаете, что сработает только обработчик первой ошибки, которая подпадает под условие.
=> here we rescue E
nil
Если мы повторно сделаем raise
в обработке ошибки, то этот raise
уже отловлен не будет и приведет к эксепшену
class E < StandardError; end
begin
raise E
rescue E
puts "here we rescue E"
raise
rescue
puts "here we rescue StandardError"
end
=> here we rescue E
E: E
from (pry):27:in '__pry__'
rescue_from из ActiveSupport::Rescuable
Если мы захотим перенести такую логику в контроллер, или у нас есть какой-то кастомный бизнес-экшен, который использует ActiveSupport::Rescuable
, то нужно помнить, что работать обработчик будет по-другому.
Пусть у нас будет вот такой базовый бизнес-экшн.
class Action
include ActiveSupport::Rescuable
def call
call_impl
rescue => ex
rescue_with_handler(ex) or raise
end
end
И мы наследуемся от него, определяя call_impl
и добавляя обработчики ошибок,
class A < Action
class E < StandardError; end
rescue_from E do |ex|
puts "here we rescue E"
raise
end
rescue_from StandardError do |ex|
puts "here we rescue StandardError"
end
def call_impl
raise E
end
end
то получим вот такой результат.
> A.new.call
here we rescue StandardError
=> #<A::E: A::E>
Дело в том, что rescue_from
работает в FILO режиме (First In Last Out), то есть последний обработчик, который мы определили, будет первым попробованным.
Поменяем местами обработчики местами
class A < Action
class E < StandardError; end
rescue_from StandardError do |ex|
puts "here we rescue StandardError"
end
rescue_from E do |ex|
puts "here we rescue E"
raise
end
def call_impl
raise E
end
end
и вот результат
irb(main):044:0> A.new.call
here we rescue E
Traceback (most recent call last):
...
1: from (irb):41:in `call_impl'
A::E (A::E)
Таким образом мы видим, что сработал именно обработчик ошибки A::E
, а не StandardError
, а так же, что raise
внутри обработчика ошибки не привел к еще повторному rescue
из StandardError
.
Top comments (0)