【发布时间】:2013-09-29 09:41:38
【问题描述】:
我有一种情况,我想要一种方法在事务中工作,但前提是事务尚未启动。这是一个人为的例子来提炼我在说什么:
class ConductBusinessLogic
def initialize(params)
@params = params
end
def process!
ActiveRecord::Base.transaction do
ModelA.create_multiple(params[:model_a])
ModelB.create_multiple(params[:model_a])
end
end
end
class ModelA < ActiveRecord::Base
def self.create_multiple(params)
# I'd like the below to be more like "ensure_transaction"
ActiveRecord::Base.transaction do
params.each { |p| create(p) }
end
end
end
class ModelB < ActiveRecord::Base
def self.create_multiple(params)
# Again, a transaction here is only necessary if one has not already been started
ActiveRecord::Base.transaction do
params.each { |p| create(p) }
end
end
end
基本上,我不希望这些充当嵌套事务。我希望.create_multiple 方法仅在尚未在事务中调用它们的情况下启动事务,例如通过ConductBusinessLogic#process!。如果模型方法被自己调用,它们应该启动自己的事务,但如果它们已经在事务内部被调用,如通过ConductBusinessLogic#process!,它们不应该嵌套子事务。
我不知道 Rails 提供这种开箱即用的方式。如果我按原样运行上面的代码并且由模型方法之一触发回滚,则整个事务仍将通过,因为子事务吞下了ActiveRecord::Rollback 异常。如果我在子事务上使用requires_new 选项,保存点将用于模拟嵌套事务,并且实际上只有那个子事务会被回滚。我想要的行为将是ActiveRecord::Base.ensure_transaction 的效果,这样只有在没有外部事务时才启动新事务,以便任何子事务都可以触发整个外部事务的回滚。这将允许这些方法自己进行事务处理,但如果有父事务,则遵从父事务。
是否有实现此行为的内置方法,如果没有,是否有可以工作的 gem 或补丁?
【问题讨论】:
标签: ruby-on-rails transactions rails-activerecord