Rails通用错误数组 [英] Rails generic errors array

查看:153
本文介绍了Rails通用错误数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



但是,我还需要能够在与Stripe API,然后导致问题,因为错误需要分配给一个特定的对象。



这是一个方法在我的 StripeCommunicator.rb class:

  def create_customer(token,object)
customer = Stripe :: Customer。创建(:description =>'住宿',:email => object.email,:card =>令牌)
返回客户

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

,你可以看到 - 这些错误被添加到@account对象 - 当我想要使用另一个控件的View来引用另一个对象来显示错误的时候,这个错误本质上使它变得无用。 / p>

任何想法?

解决方案

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

  def create_customer(token,object,model_instance)
条纹: :Customer.create(description:'Accommodation',email:object.email,card:token)
#return customer< - 不需要这个。任何最后评估将返回
rescue Stripe :: CardError => e
model_instance.errors.add:base,e.message
false
end

如果您在控制器中执行错误处理而不是服务对象,则可以利用 rescue_from 来处理从动作方法中删除的异常,例如在您的控制器或ApplicationController等中,执行以下操作:

  rescue_from Stripe :: CardError,其中::add_error_message_to_base 

def add_error_message_to_base(e)
#这假设你在控制器的action方法中设置@instance。
@ 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 放入包含的块中:

 模块StripeErrorHandling 
extend :: ActiveSupport :: Concern

包含do
rescue_from Stripe :: CardError,其中::add_error_message_to_base
end

def add_error_message_to_base(e)
#查看上面的注释...
@instance .errors.add:base,e.message
respond_with @instance
end
end

您可以使用 config.exceptions_app 来处理机架级别的错误,因为JoséValim描述这里



您还可以继承该方法,而不是使用单独的服务类,或者具有关注/模块。你甚至可以通过钩子,例如:

 #不完全是你在做什么,只是举个例子。 
#可以在其他地方放入应用/控制器/关注点。
模块ActionsCreateStripeCustomer
extend :: ActiveSupport :: Concern

包含do
around_action:create_stripe_customer
end

def create_stripe_customer
#这个(间接的)调用action方法,在这个例子的action方法中你将
#set @instance。
yield
customer = Stripe :: Customer.find_or_create_by(描述:住宿,电子邮件:object.email,卡:令牌)
#可以将客户设置为@instance,并在需要时保存等等
rescue Stripe :: CardError => e
如果@instance
@ instance.errors.add:base,e.message
respond_with @instance
else
logger.warn(Expected @instance to be由#{self.class.name} ## {params [:action]}设置)
raise e
end
end
end

然后在控制器中:

 包括ActionsCreateStripeCustomer 

还有 before_action after_action 等等。此外,您可以只包含模块,当调用实例方法时,它们首先调用包含类实例,然后调用第一个包含的模块,然后再调用第二个。如果您定义了 super(超级)调用先前的方法,它会自动输入所有的参数和块。



而且,如果是关于获取模型类名称而不是实例,那么也很容易。说你打来的课是AccountStripeCommunicator,然后是 @model_class ,以下是帐号:

  qualified_class_name = self.class.name.chomp('StripeCommunictor')
@model_class = qualified_class_name.split('::')。last.singularize.constantize

各种可能性。


In my Rails 4 app I have a Service object that handles communication with Stripe Payments Processor. I want it as a service object so that multiple Controllers/Models can utilize the methods within it.

However, I also need to be able to trap errors when communicating with the Stripe API which then causes the problem as the errors need to be assigned to a particular object.

Here is a method in my 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

as you can see - the errors are being added to the @account object - which essentially renders it useless when I want to use this method from another controller with a View that refers to another object to display errors.

Any ideas?

解决方案

Simplest thing is to just pass the @account instance in as another argument. Errors is going to be on any model instance, e.g.

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

If you were doing the error handling in the controller instead of a service object, you could take advantage of rescue_from which can handle exceptions falling out from action methods, e.g. in your controller or ApplicationController, etc., do the following:

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

or more generically:

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

or in a concern, you could do either of the above, putting the rescue_from into the included 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

And you can use config.exceptions_app to handle errors at the Rack-level as José Valim describes here.

You could also inherit the method vs. having a separate service class, or have a concern/module. You might even do through hooks, e.g.:

# 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

Then in the controller:

include ActionsCreateStripeCustomer

There is also before_action, after_action, etc. Also, you can just include modules and when instance methods are called they call on the including class instance first, then the first included module, then the second, etc. if you do super if defined?(super) to call the prior method, and it automatically puts in all the arguments and block.

And, if it were about getting the model class name rather than the instance, that is easy, too. Say the class you were calling from was AccountStripeCommunicator, then @model_class after the following would be Account:

qualified_class_name = self.class.name.chomp('StripeCommunictor')
@model_class = qualified_class_name.split('::').last.singularize.constantize

All kinds of possibilities.

这篇关于Rails通用错误数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆