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

问题描述 投票:0回答:3

我已经在

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

对此有什么建议吗?

ruby-on-rails rspec
3个回答
6
投票

TL;博士

@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 方法上运行 after_commit - do_something。发生这种情况是因为在 (
@work_order
) 创建
@work_order = WorkOrder.create(status_id: 1, order_id: 2)
之后,名为
@_start_transaction_state
的实例变量被初始化,但从未被清除。据我通过阅读代码了解,
@_start_transaction_state
在ActiveRecord::Transaction模块中用于跟踪事务处理。

因此,在调用

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) 

我知道这个解决方案很糟糕,我不确定这是否会带来一些副作用,尤其是嵌套事务,但这是 Rails 4.0.1 中唯一对我有用的变体。


4
投票

根据 documentation,您需要使用 test_after_commit gem 才能在测试中触发

after_commit
钩子。 Rails 5.0+ 将不再需要这个。

另一种选择是将以下代码放在 it 块主体的末尾:

subject.run_callbacks(:commit)

0
投票

对我来说,我在这个评论中找到了答案:https://stackoverflow.com/a/75404278/5808008

他们的关键部分是

instance_variable_set(:@_trigger_update_callback, true)

© www.soinside.com 2019 - 2024. All rights reserved.