Rails通用错误数组 [英] Rails generic errors array
问题描述
在我的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屋!