【发布时间】:2016-08-22 10:56:24
【问题描述】:
让我们为这个问题提供一些背景信息。给定一个 Ruby on Rails 中的电子商务应用程序。让我们以 2 个模型为例。用户和信用卡。
我的用户在注册后在系统中没有问题。 CreditCard 是带有信用卡信息的模型(是的,我知道 PCI 合规性,但这不是重点)
在信用卡模型中,我包含一个回调 after_validation,它将针对您的银行验证信用卡。
让我在这里放一些简单的代码。
models/user.rb
class User < ActiveRecord::Base
enum :status, [:active, :banned]
has_one :credit_card
end
models/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
controllers/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 中打开了一个事务。此时没有任何内容发送到数据库。
当银行拒绝信用卡时,我想禁止用户。我通过调用禁止来做到这一点!现在我意识到这个更新是针对同一个事务的。我可以看到更新,但是一旦保存不去,一切都会从两个模型中回滚。信用卡没有保存(很好),用户没有保存(这个不好,我要封他)
我尝试添加一个事务包装器,但这只会添加一个数据库检查点。我可以为禁令创造一个延迟的工作,但在我看来,这似乎是矫枉过正。我可以使用 after_rollback 回调,但我不确定这是正确的方法。我有点惊讶,我以前从未遇到过这种情况,这让我相信我的模式不正确,或者我做出这个调用的点不正确。
【问题讨论】:
-
好吧,我一定是在某个地方搞砸了,因为我无法在侧面项目上复制它。无论如何我都会调查并至少发布这个问题的解决方案。
-
Ok 控制器中的@credit_card.save 开始交易。这很好,这是有道理的。现在,如果我想在交易开始时调用 user.update_column(info: "Not well") 我该怎么做?
-
找到了一些关于并行处理的资料。 stackoverflow.com/a/20743433/552443 您可以通过启动一个线程并从连接池重新连接数据库来完成此操作。我确定这是可行的,但我发现这种简单的表格更新有点过头了。希望有人能提出一些想法。
标签: ruby-on-rails activerecord model transactions