让我们对这个问题提出一些背景信息。给出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回调,但我不确定这是正确的方法。我有点意外,我之前从未接触到这种情况,让我相信我的模式不正确或者我打电话的地方不正确。
答案 0 :(得分:0)
经过多次审查和更多挖掘后,我提出了3种方法来处理这种情况。根据您的需求,其中一个应该对您有好处。
将要执行的任务发送到延迟作业
以下答案显示了如何执行此操作。
https://stackoverflow.com/a/20743433/552443
这样可行,但又不是那么好又简单。
这是一个非常快速的解决方案。问题是新开发者可以删除有效的?认为.save能够正常完成这项工作。
这可以是任何ActionJob提供者。您可以将任务发送到单独的线程中禁止用户。根据您的设置,这非常干净,但不是每个人都需要DelayedJob。
如果您看到任何内容,请将其添加到评论的新解决方案中。