Лучший способ сломать и вернуть значение - PullRequest
0 голосов
/ 05 июля 2018

У меня есть метод, который вложен в пару других методов, и я хочу, чтобы этот метод break из всех рекурсивных методов с возвращенной ошибкой. Например, если мне звонят pay_order здесь:

class API::StripeController < ApiController
  def my_api_action
    # ...
    order = create_order
    pay_order(order, token)
    # do things if payment is successful
  end
end

А pay_order определяется как:

def pay_order(order, token)
  begin
    order.pay(source: token)
  rescue Stripe::CardError => e
    break e
  end
end

Как мне выйти из всех родительских методов и вернуть ошибку карты, возникшую из-за неудавшегося платежа? Мне нужно что-то вроде break and return e или return e and break. Но я знаю, что операторы break и return немедленно возвращаются, поэтому я не могу их связать (я не думаю).

Я мог бы просто добавить return операторов к каждой вызываемой функции, но я планирую использовать этот метод во многих местах, и не планирую когда-либо, чтобы он вел себя по-другому, поэтому я ищу наиболее многоразовый способ написать это.

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

В основном вы можете использовать throw или raise (соответственно fail, см. здесь для обсуждения, использовать ли raise или fail).

Разница в том, что при повышении / сбое вы создаете исключение (которое вы ловите с помощью rescue), а объект Exception может содержать в качестве полезной нагрузки данные, которые вы хотите вернуть.

С throw вы просто делаете goto вверх по цепочке вызовов. Точка приземления определяется с помощью catch (см., Например, здесь ). Это не имеет никакой полезной нагрузки, что означает, что вам нужно «транспортировать» любые данные обратно, используя объект, который доступен с обеих сторон (например, переменная экземпляра).

0 голосов
/ 05 июля 2018

Почему вы rescue внутри pay_order метода? Я бы спас на внешней петле. Учитывая следующее:

def method_a
  10.times do |loop_a|
    method_b
  end
end

def method_b
  5.times do |loop_b|
    pay_order
  end
end

def pay_order
  ...
end

Я бы спасал внутри method_a, например:

def method_a
  10.times do |loop_a|
    method_b
  end
rescue Stripe::CardError => e
  # do whatever. no need to break
end

Все циклы автоматически "разрываются" при возникновении исключения.

Если вы хотите что-то сделать с исключением внутри метода pay_order, я бы предложил спасти и снова поднять:

def pay_order
  order.pay
rescue Stripe::CardError => e
  # do your stuff
  raise e
end
...