我有一种情况,我想要一种在事务中工作的方法,但前提是事务尚未启动。这是一个人为的例子来提炼我在说什么:
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!
. 如果模型方法被自己调用,它们应该启动自己的事务,但如果它们已经在事务内部被调用,如 through ConductBusinessLogic#process!
,它们不应该嵌套子事务。
我不知道 Rails 提供这种开箱即用的方式。如果我按原样运行上面的代码并且模型方法之一触发了回滚,那么整个事务仍然会通过,因为子事务会吞下ActiveRecord::Rollback
异常。如果我使用requires_new
在子事务上使用该选项,将使用保存点来模拟嵌套事务,并且实际上只有那个子事务会被回滚。我想要的行为会影响到ActiveRecord::Base.ensure_transaction
,例如只有在没有外部事务时才启动新事务,以便任何子事务都可以触发整个外部事务的回滚。这将允许这些方法本身是事务性的,但如果有父事务,则遵从父事务。
是否有实现此行为的内置方法,如果没有,是否有可以工作的 gem 或补丁?