March 1, 2015
after_commit
callback in Rails is triggered
after the end of transaction.
For eg. I have a Post model
for which
the number of lines
of the content
are calculated in the after_commit
callback:
class Post < ActiveRecord::Base
after_commit :calculate_total_lines, if: -> (post) { post.previous_changes.include?(:content) }
def calculate_total_lines
update! total_lines: content.split("\n").length
end
end
post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh'
assert_equal 1, post.total_lines
Now lets wrap the creation of post inside a transaction block:
Post.transaction do
post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh'
assert_equal 1, post.total_lines
end
The test will fail now.
# 1) Failure:
# BugTest#test_within_transaction [after_commit_test.rb:45]:
# Expected: 1
# Actual: nil
Why? Lets recall. after_commit
callback will get executed
after the end of transaction.
So until all the code inside transaction is completed, the callback is not going to get executed.
Here is a gist with complete test.
Next time you are using an after_commit
callback and a transaction
,
make sure that code inside the transaction is not dependent on the
result of the callback.
If this blog was helpful, check out our full blog archive.