ruby-on-rails - Rails 通用错误数组

标签 ruby-on-rails error-handling ruby-on-rails-4

在我的 Rails 4 应用程序中,我有一个 Service 对象来处理与 Stripe Payments Processor 的通信。我希望它作为服务对象,以便多个 Controller /模型可以利用其中的方法。

但是,我还需要能够在与 Stripe API 通信时捕获错误,这会导致问题,因为需要将错误分配给特定对象。

这是我的 StripeCommunicator.rb 中的一个方法类(class):

def create_customer(token,object)
  customer = Stripe::Customer.create(:description => 'Accommodation', :email => object.email, :card => token)
  return customer

rescue Stripe::CardError => e
  @account.errors.add :base, e.message
  false
end

正如你所看到的 - 错误被添加到 @account 对象 - 当我想从另一个 Controller 使用这个方法时,它基本上变得无用,而 View 引用另一个对象来显示错误。

有任何想法吗?

最佳答案

最简单的事情就是通过 @account作为另一个参数的实例。错误将出现在任何模型实例上,例如

def create_customer(token,object,model_instance)
  Stripe::Customer.create(description: 'Accommodation', email: object.email, card: token)
  # return customer <- don't need this. whatever is last evaluated will be returned
rescue Stripe::CardError => e
  model_instance.errors.add :base, e.message
  false
end

如果您在 Controller 而不是服务对象中进行错误处理,您可以利用 rescue_from它可以处理从 Action 方法中产生的异常,例如在您的 Controller 或 ApplicationController 等中,执行以下操作:
rescue_from Stripe::CardError, with: :add_error_message_to_base

def add_error_message_to_base(e)
  # this assumes that you set @instance in the controller's action method.
  @instance.errors.add :base, e.message
  respond_with @instance
end

或更笼统地说:
rescue_from Stripe::CardError, with: :add_error_message_to_base

def add_error_message_to_base(e)
  model_class_name = self.class.name.chomp('Controller').split('::').last.singularize
  instance_value = instance_variable_get("@#{model_class_name}")
  instance_value.errors.add :base, e.message if instance_value
  respond_with instance_value
end

或担心,您可以执行上述任一操作,将 rescue_from进入包含的 block :
module StripeErrorHandling
  extend ::ActiveSupport::Concern

  included do
    rescue_from Stripe::CardError, with: :add_error_message_to_base
  end

  def add_error_message_to_base(e)
    # see comment above...
    @instance.errors.add :base, e.message
    respond_with @instance
  end
end

您可以使用 config.exceptions_app正如 José Valim 所描述的那样,在机架级别处理错误 here .

您也可以继承该方法而不是拥有一个单独的服务类,或者有一个关注点/模块。你甚至可以通过钩子(Hook)来做,例如:
# not exactly what you were doing but just for example.
# could put in app/controller/concerns among other places.
module ActionsCreateStripeCustomer
  extend ::ActiveSupport::Concern

  included do
    around_action :create_stripe_customer
  end

  def create_stripe_customer
    # this (indirectly) calls the action method, and you will
    # set @instance in your action method for this example.
    yield
    customer = Stripe::Customer.find_or_create_by(description: 'Accommodation', email: object.email, card: token)
    # could set customer on @instance here and save if needed, etc.
  rescue Stripe::CardError => e
    if @instance
      @instance.errors.add :base, e.message
      respond_with @instance
    else
      logger.warn("Expected @instance to be set by #{self.class.name}##{params[:action]}")
      raise e
    end
  end
end

然后在 Controller 中:
include ActionsCreateStripeCustomer

还有before_action , after_action等等。另外,你可以只包含模块,当实例方法被调用时,它们首先调用包含类实例,然后是第一个包含的模块,然后是第二个,等等。如果你这样做 super if defined?(super)调用先前的方法,它会自动放入所有参数和 block 。

而且,如果是关于获取模型类名称而不是实例,那也很容易。假设您调用的类(class)是 AccountStripeCommunicator,然后是 @model_class以下将是帐户:
qualified_class_name = self.class.name.chomp('StripeCommunictor')
@model_class = qualified_class_name.split('::').last.singularize.constantize

各种可能性。

关于ruby-on-rails - Rails 通用错误数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19258343/

相关文章:

php - 拥有更有效的代码以返回错误

ruby-on-rails - 获取对应 Controller Action View 文件的路径

ruby-on-rails - 如何断言它使用正确的 json 呈现?

android - 执行doInBackground()时发生错误-Android小部件

ruby-on-rails - Rails 应用程序在本地运行,在 Heroku 上崩溃

ruby-on-rails - Rails 3 HTTP-header If-Modified-Since 使用 curl

ruby-on-rails - Rails 4 : setting request. 格式不更新 params[:format]

sql - MS SQL Server : how to determine which field is causing Arifmetic error

postgresql - Rails 对 csv 格式的原始查询,将通过 Controller 返回

ruby-on-rails - 在 Active Record 迁移中可逆和还原