干重复的救援声明

时间:2017-01-18 00:57:14

标签: ruby error-handling

我使用stripe作为支付处理器。

在应用程序中,我向Stripe发送执行费用或其他类型进程的请求,并且基本上使用与下面相同的错误处理样板。

rescue Stripe::InvalidRequestError => e,  
  # do something
rescue Stripe::AuthenticationError => e, 
  # do something
rescue Stripe::APIConnectionError => e, 
  # do something
rescue Stripe::StripeError => e
  # do something
rescue => e
  # do something
end

虽然我在每个API调用中肯定rescue这些错误类型,这是很多样板代码,但我只想在所有这些错误类型上rescue,然后构建一个方法做日志记录,发送通知等事情。

如何以更干净的方式将这些捆绑到一个异常处理程序中(如下所示)?

def call
   plan = Plan.new(attrs)
   return plan unless plan.valid?

   begin
     external_card_plan_service.create(api_attrs)
   rescue Exceptions::Stripe => e
     plan.errors[:base] << e.message
     return plan
   end

   plan.save
   plan.update(is_active: true, activated_at: Time.now.utc)
   plan
 end

3 个答案:

答案 0 :(得分:4)

在您的应用中的某个位置定义一个变量/常量/方法,它返回您要营救的错误列表。例如:

STRIPE_ERRORS = [Stripe::InvalidRequestError, String::AuthenticationError]

在救援区中,您可以使用splat操作员来解救其中任何一个:

   begin
     <raise errors>
   rescue *STRIPE_ERRORS => e
     <handle errors>
   end

您可以查看使用e.class

引发的错误

答案 1 :(得分:4)

不完全确定do something是否与每种情况相同。如果没有,这可能会做你想要的:

def handle_stripe_errors
  yield
rescue Stripe::AuthenticationError => e, 
  # do something
rescue Stripe::APIConnectionError => e, 
  # do something
rescue Stripe::StripeError => e
  # do something
rescue => e
  # do something
end

handle_stripe_errors do
  external_card_plan_service.create(api_attrs)
end

答案 2 :(得分:1)

这是与Max和Amadan的解决方案相结合的另一种解决方案,它使DRY的功能更多一些,并成为可重用的类。

该解决方案利用了Rails around_action,您可以在其中围绕其方法定义控制器中的动作。

...
STRIPE_ERRORS = [Stripe::InvalidRequestError, String::AuthenticationError, ...]

around_action :stripe_error_handler
...

def stripe_error_handler
  yield
rescue *STRIPE_ERRORS => e
     <handle errors>
end
...

**您可以指定around_action适用于哪些方法!

要使其更具可重用性,您可以定义一个包含常量STRIPE_ERRORS的类,并在救援部分(StripeErrorHander.new(e)中用e初始化,这样您可以指定每个Stripe错误的行为(也许发送一个电子邮件/闲置邮件中出现的特定错误,请使该错误邮件更具可读性)。

对类的简化外观可能是这样的:

class StripeErrorHandler
  STRIPE_ERRORS = [
    Stripe::CardError,
    Stripe::RateLimitError,
    ...
  ].freeze

  def initialize(error)
    @error = error
  end

  def message
    @error.message
  end

  def status
    case @error
    when Stripe::CardError
      :unprocessable_entity
    when Stripe::RateLimitError
      :service_unavailable
    else
      :internal_server_error
    end
  end
end