Возьмем пример
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)