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