如何判断 ActiveRecord::Base.transaction 块何时提交?

Joh*_*lly 5 ruby-on-rails rails-activerecord

后台作业和 ActiveRecord 的一个常见问题是作业所需模型提交到数据库之前排队并执行。

ActiveRecord 模型有一个很好的after_commit回调,可用于特定模型。

但是,假设您有一些涉及几个不同模型的业务逻辑,将这些逻辑塞进单个模型中是不合适的。因此,您编写某种服务/命令对象来执行事务块内的逻辑:

例如,类似于以下内容:

class SomeServiceObject

  def execute
    thing = create_thing_in_a_tx

    # this notification often fires before the above transaction commits.
    notify_user(thing)
  end

  private

  def create_thing_in_a_tx
    ActiveRecord::Base.transaction do
      a = ModelA.new(foo: 'bar')
      b = ModelB.new(a_record: a, biz: 'baz')
      #... various other logic that doesn't really belong in a model ...
      ThingModel.create!(b_record: b)
    end
  end

  def notify_user(thing)
    EnqueueJob.process_asyc(thing.id)
  end
end
Run Code Online (Sandbox Code Playgroud)

在这种情况下,据我所知,您实际上无法访问方便的after_commit回调。

我想在上面的示例中,您可以ThingModel将作业排入其after_commit回调中,但是随后您将应承担的责任分散SomeServiceObject到不同的类中,这感觉不对。

鉴于上述所有内容,是否有任何合理的方法可以知道ActiveRecord::Base.transaction块何时提交,而无需求助于任何特定模型的after_commit回调?

谢谢!:-D

(另请参阅:如何强制 Rails ActiveRecord 提交事务刷新

Bil*_*hty 6

这比您想象的要简单。区块完成后ActiveRecord::Base.transaction,交易已被提交。

def create_thing_in_a_tx
  begin
    ActiveRecord::Base.transaction do
      a = ModelA.new(foo: 'bar')
      b = ModelB.new(a_record: a, biz: 'baz')
      #... various other logic that doesn't really belong in a model ...
      ThingModel.create!(b_record: b)
    end
    # The transaction COMMIT has happened.  Do your after commit logic here.
  rescue # any exception
    # The transaction was aborted with a ROLLBACK.  
    # Your after commit logic above won't be executed.
  end
end
Run Code Online (Sandbox Code Playgroud)