【问题标题】:Rails service objectsRails 服务对象
【发布时间】:2013-10-18 05:57:39
【问题描述】:

我正在使用服务对象将条纹支付功能抽象到它自己的类中。我正在使用这种方法https://gist.github.com/ryanb/4172391 ryan bates 谈到的。

class Purchase
  def initialize(order)
    @order = order
  end

  def create_customer
    customer = stipe create customer
    if customer
       charge_customer(customer)
    else
       stipe error in creating customer
    end
  end

  def charge_customer(customer)
      if charge is sucessfull
         update_order(charge details)
      else
         stripe error in charging card
      end     
  end
  def update_order
     @order.update(payment attributes)
  end
end

然后在订单控制器中我正在做类似的事情

def create
@order = Order.new(params[:order])
 if @order.save
    payment = Payment.new(@order)
 else 
   render 'new' with flash message "payment error"
 end
end

我的问题是,我如何获得显示给用户的 stipe 错误消息(“创建客户时出现错误”和“收费卡中出现条纹错误”)? 或者我可以在订单模型中调用服务对象并将其添加到订单错误消息中吗?例如,
订单控制器

@order.save_with_payment

订单型号

def save_with_payement
   payment = Payment.new(self)
   #update order 
   self.payment_token = payment.token
   etc
end

如果我可以用模型做到这一点,我如何进行显示条纹错误的验证?
提前致谢。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 stripe-payments service-object


    【解决方案1】:

    首先尝试尽可能分离关注点。已经感觉 Your Purchase/Payment 类做的太多了,可能它应该将部分例程委托给其他服务对象。

    其次,我同意 phoet。我看不出您不将参数哈希传递给服务对象的原因。在我们最新的项目中,我们完全依赖我们称为工厂的服务对象来生产/操作我们的模型对象。在您的情况下,您可以这样做:

    class OrderFactory
      def self.create(params)
        new(params).create
      end
    
      def initialize(params)
        @order = Order.new(params[:order])
      end
    
      def create
        @payment = Payment.new(self)
        @order.payment_token = payment.token
        #....
      end
    end
    

    谈论验证 - 您可以将验证方法添加到普通的 Ruby 对象。例如通过使用 ActiveModel: http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/ 然后您可以创建自定义验证器,like Ryan suggested

    或者您可以使用像 Virtus 这样的 gem 并添加一些自定义验证规则。

    【讨论】:

    • 参数概率。是因为参数中的很多内容都是受保护的属性,需要在手动更新它们之前与其他模型值进行检查,但是谢谢,我会看看这些链接并立即尝试。
    • 这与我已经发布的内容并不矛盾。您可以在 Your Order 模型上创建一个方法来执行此自定义分配逻辑。或者将此逻辑封装在 OrderFactory 中的另一个方法中,甚至是单独的对象中。
    【解决方案2】:

    我认为服务应该负责处理这一切。所以它可能看起来像这样

    def create
      @payment = Payment.new(params[:order])
      if @order = @payment.execute_transaction
        [...]
      else 
        [...]
      end
    end
    

    因此支付服务将处理订单的创建和持久化,并且还可能添加验证错误。您还可以返回某种@result 对象,该对象可能包含订单和相关错误消息。

    【讨论】:

    • 嘿,谢谢您的回答,唯一的问题是我在 params[:order] 中有很多受保护的属性,这些属性将手动设置和验证,例如使用 product_id 获取产品并检查如果产品等于 params[:order] 中的金额,并设置要从使用产品 ID 找到的产品中收取的金额,因为任何人都可以轻松绕过 JavaScript 金额验证。有没有办法从支付类中设置受保护的属性?
    • 您将不得不重构您的类以使其与此类服务一起使用。
    • 我认为如果你使用强参数而不是 attr_accesible 等,你可以让控制器只将允许的参数传递给服务对象;否则参数错误可能会在它到达之前停止处理。
    • 哦,我明白了,这就是强参数的作用。不幸的是,我仍在 Rails 3 上,有没有办法在 Rails 3 中复制类似的东西?
    【解决方案3】:

    就在一天前,我问了一个非常相似的问题。我收到的回复确实很有帮助(感谢@gary-s-weaver),所以看看吧。

    Rails generic errors array

    我最终采用了 rescue_from 方法,它对我来说效果很好。让我知道你的进展,因为我对这个领域非常感兴趣。如果您需要任何代码示例,请给我留言。

    【讨论】:

      【解决方案4】:

      我为服务对象编写了一个 gem。查看peafowl gem。

      【讨论】:

        猜你喜欢
        • 2013-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-09
        • 1970-01-01
        • 2015-09-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多