`update`上的`after_commit`回调不会触发

时间:2015-11-26 13:44:28

标签: ruby-on-rails rspec

我在after_commit上定义了update回调。它不会在rspec中触发。

这是我的回调:

after_commit :notify_trip, :if => Proc.new { |trip| trip.can_send_schedule_notification? }, on: :update

这是我的rspec代码:

@work_order.update_attributes(:status_id => statuses(:scheduled).id, :tour_id => @tour.id)
@work_order.run_callbacks(:commit)
assert_equal 1, ActionMailer::Base.deliveries.size
expect(ActionMailer::Base.deliveries[0].to).to include(@user.email)
expect(ActionMailer::Base.deliveries[0].subject).to include("Your trip has been scheduled!")

此处回调未调用且ActionMailer::Base.deliveries.size返回0

对此有任何建议。

2 个答案:

答案 0 :(得分:3)

根据documentation,您需要使用test_after_commit gem来在测试中触发after_commit个钩子。在rails 5.0 +上将不再需要这个。

另一个替代方法是将以下代码放在it块正文的末尾:

subject.run_callbacks(:commit)

答案 1 :(得分:3)

<强> TL; DR

@work_order.update_attributes(:status_id => statuses(:scheduled).id, :tour_id => @tour.id)
@work_order.instance_variable_set(:@_start_transaction_state, {})
@work_order.run_callbacks(:commit)

<强>解释

我和Rails 4.0.1有类似的情况:

@work_order = WorkOrder.create(status_id: 1, order_id: 2)
@work_order.update_attributes(status_id: 4, order_id: 5)
@work_order.run_callbacks(:commit)

当模型实现看起来像这样:

class WorkOrder < ActiveRecord::Base
  after_commit :notify_trip, :if => Proc.new { |trip| trip.can_send_schedule_notification? }, on: :update
  after_commit :do_something, on: :create
end

每当我调用@work_order.run_callbacks(:commit)时,它都会在create方法 - do_something上运行after_commit。这是因为在@work_order创建了@work_order = WorkOrder.create(status_id: 1, order_id: 2)之后,一个名为@_start_transaction_state的实例变量被初始化,但从未被清除。在我阅读代码时,ActiveRecord :: Transaction模块中使用@_start_transaction_state来跟踪事务处理。

因此,如果我们清除run_callbacks,则在致电@_start_transaction_state之前,我们将能够运行after_commit on: update回调

@work_order.instance_variable_set(:@_start_transaction_state, {})
@work_order.run_callbacks(:commit) 

还有一个更清洁的选择:

@work_order.send(:clear_transaction_record_state)
@work_order.run_callbacks(:commit) 

我知道解决方案是hacky,我不确定这是否会引入一些副作用,特别是对于嵌套事务,但是在Rails 4.0.1中唯一适用于我的变体。