将错误从 ActiveRecord 事务传递给用户

Passing errors to user from ActiveRecord transaction

我有这样的交易

  def accept_transaction
    Purchase.transaction do
      save! #Validate and Save purchase
      product.update_bought
      user.charge!(product.price)
      Investment.add_spent(user_id: user.id,
                                spent: product.price)
  end

我想完成的是在交易未完成时向 Errors 对象添加相应的错误消息。所以所需的方法看起来像

  def accept_transaction
    Purchase.transaction do
      save! #Validate and Save purchase(adds validation errors by default)
      add_out_of_stock_error unless product.update_bought
      add_no_money_error unless user.charge!(product.price)
      other_error unless Investment.add_spent(user_id: user.id,
                                spent: product.price)
  end

  def add_out_of_stock_error
    errors[:base].add("Product not available")
  end
  def no_money_error
   ...
  end
  def other_error
  ...
  end

现在我无法得到想要的结果,这些操作在失败的情况下会引发 ActiveRecord::Rollback 错误并且不会触发错误方法。

听起来您想使用 save 而不是 save!

save! 如果验证失败则引发异常 http://apidock.com/rails/ActiveRecord/Base/save!

save returns 错误 http://apidock.com/rails/ActiveRecord/Base/save

所以你可以这样做: unless save # add errors end

但请注意两者都回滚了事务。

我想出的解决方案(也感谢@lcguida)。有点简单

def accept_transaction
    Purchase.transaction do
      save! #Validate and Save purchase(adds validation errors by default)
      catch_out_of_stock_error { product.update_bought }
      catch_no_money_error { user.charge!(product.price) }
      catch_other_error { Investment.add_spent(user_id: user.id,
                                spent: product.price) }
  end

  def catch_out_of_stock_error &block
    begin
      yield
    rescue ActiveRecord::Rollback => e
      errors.add(:base,"Product not available")
      raise e
    end
  end
  def catch_no_money_error &block
   ...
  end
  def catch_other_error &block
  ...
  end

我的想法是,对于每个错误,我都有一个单独的方法,我在其中传入可能导致错误的方法。然后我在一个孤立的环境中从 ActiveRecord::Rollback 中拯救出来,附加错误并重新引发相同的错误。

有问题请post再回答easier/better。