ActiveRecord更新模型,同时回滚另一个

时间:2016-04-27 22:05:08

标签: ruby-on-rails activerecord model transactions

让我们对这个问题提出一些背景信息。给出Ruby on Rails中的电子商务应用程序。我们以两个模型为例。用户和CreditCard。

我的用户在注册后没有问题在系统中。 CreditCard是一个带有信用卡信息的模型(是的,我知道PCI合规性,但这不是重点)

在信用卡模式中,我提供了一个回调after_validation,它将对您的银行进行信用卡验证。

我在这里放一些简单的代码。

模型/ user.rb

class User < ActiveRecord::Base
  enum :status, [:active, :banned]
  has_one :credit_card
end

模型/ credit_card.rb

class CreditCard < ActiveRecord::Base
  belongs_to :user

  after_validation :validate_at_bank

  def validate_at_bank
    result = Bank.validate(info) #using active_merchant by exemple
    unless result.success
      errors.add {credit_card: "Bank doesn't validate"}
      user.banned!
    end
  end
end

控制器/ credit_cards_controller.rb

class CreditCardsController < ApplicationController
  def create
    @credit_card = CreditCard.new(credit_card_params) # from Strong Parameters
    if @credit_card.save
      render #success
    else
      render #failure
    end
  end
end

导致我问题的原因 当我正在做一个新的时,看起来Rails在ActiveRecord中打开一个事务。此时没有任何内容发送到数据库。

当银行拒绝信用卡时,我想禁止用户。我通过打电话禁止这样做!现在我意识到这个更新将进入同一个事务。我可以看到更新,但是一旦保存不通过,一切都从两个模型回滚。信用卡没有保存(这很好),用户没有保存(这是不好的,因为我想禁止他)

我尝试添加一个Transaction包装器,但这只添加一个数据库检查点。我可以为禁令创造一个延迟的工作,但在我看来这似乎有点矫枉过正。我可以使用after_rollback回调,但我不确定这是正确的方法。我有点意外,我之前从未接触到这种情况,让我相信我的模式不正确或者我打电话的地方不正确。

1 个答案:

答案 0 :(得分:0)

经过多次审查和更多挖掘后,我提出了3种方法来处理这种情况。根据您的需求,其中一个应该对您有好处。

  1. 单独的线程和新的数据库连接
  2. 在明确保存之前调用验证功能
  3. 将要执行的任务发送到延迟作业

    • 单独的帖子

    以下答案显示了如何执行此操作。

  4. https://stackoverflow.com/a/20743433/552443

    这样可行,但又不是那么好又简单。

    • 通话有效吗?在保存之前

    这是一个非常快速的解决方案。问题是新开发者可以删除有效的?认为.save能够正常完成这项工作。

    • 致电延迟工作

    这可以是任何ActionJob提供者。您可以将任务发送到单独的线程中禁止用户。根据您的设置,这非常干净,但不是每个人都需要DelayedJob。

    如果您看到任何内容,请将其添加到评论的新解决方案中。