Reputation: 302
I have defined after_commit
callback on update
. It doesn't trigger in rspec.
Here is my callback :
after_commit :notify_trip, :if => Proc.new { |trip| trip.can_send_schedule_notification? }, on: :update
Here is my rspec code :
@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!")
Here callback is not calling and ActionMailer::Base.deliveries.size
returning 0
Is there any suggestion on this.
Upvotes: 7
Views: 5763
Reputation: 166
For me, I found the answer in this comment: https://stackoverflow.com/a/75404278/5808008
They key part is instance_variable_set(:@_trigger_update_callback, true)
Upvotes: 0
Reputation: 1512
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)
Explanation
I had a same similar situation with 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)
when the model implementation look something like this:
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
and every time when I call @work_order.run_callbacks(:commit)
then it would run the after_commit on create method - do_something. That happens because after the @work_order
is created by (@work_order = WorkOrder.create(status_id: 1, order_id: 2)
) a instance variable called @_start_transaction_state
is initialized, but never cleared. @_start_transaction_state
is used in ActiveRecord::Transaction module to track a transaction process as far as I understood from reading the code.
So before calling run_callbacks
if we clear up @_start_transaction_state
, then we will be able to run the after_commit on: update
callbacks
@work_order.instance_variable_set(:@_start_transaction_state, {})
@work_order.run_callbacks(:commit)
There's one more option which is a little bit cleaner:
@work_order.send(:clear_transaction_record_state)
@work_order.run_callbacks(:commit)
I know that the solution is hacky and I'm not sure if that might introduce some side effects, especially with nested transactions, but was the only variant that worked for me in Rails 4.0.1.
Upvotes: 6
Reputation: 7540
According to documentation, you need to use the test_after_commit gem to have after_commit
hooks get fired in tests. this will be no longer needed on rails 5.0+.
Another alternative could be putting following code at the end of the body of the it block:
subject.run_callbacks(:commit)
Upvotes: 4