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:
1class Post < ActiveRecord::Base 2 after_commit :calculate_total_lines, if: -> (post) { post.previous_changes.include?(:content) } 3 4 def calculate_total_lines 5 update! total_lines: content.split("\n").length 6 end 7end
1post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh' 2assert_equal 1, post.total_lines
Now lets wrap the creation of post inside a transaction block:
1Post.transaction do 2 post = Post.create! content: "Lets discuss Rails 5.\n", author: 'Prathamesh' 3 assert_equal 1, post.total_lines 4end
The test will fail now.
1# 1) Failure: 2# BugTest#test_within_transaction [after_commit_test.rb:45]: 3# Expected: 1 4# 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.