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

时间:2016-08-18 16:07:53

标签: ruby-on-rails rails-activerecord

具有后台作业和ActiveRecord的common problem是在将所需模型提交到数据库之前将作业排队并执行的时间。

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

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

我想在上面的示例中,您可以ThingModelafter_commit回调中的作业排入队列,但是然后您将SomeServiceObject的责任分散到不同的ActiveRecord::Base.transaction类,感觉错误。

鉴于上述所有情况,是否有任何合理的方法可以知道after_commit阻止何时提交,而不诉诸任何特定模型的"=="回调?

谢谢! :-D

(另见:How to force Rails ActiveRecord to commit a transaction flush

1 个答案:

答案 0 :(得分:1)

它比你想象的要简单。 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