Gotcha: Rails callback that checks changed fields

Recently I saw a post that explained a gotcha around Rails with the use of callbacks when checking for changed fields. This gotcha does exist but there is an easy solution.

The problem

If you want to queue a job if a column has changed you could do something like this;

before_save :do_something, if: :field_changed?
def do_something
MyJob.perform(id)
end

The issue here is that when your job finds the object it might not yet have been committed to the database so it will have the old attributes. To get around this, you can use after_commit instead of before_save. However because the save has already occurred, field_changed? is not longer available.

The solution

If the save has already occurred you can then use previous_changes to check what was changed, which returns a Hash of changes with the keys as the fields changed and the values being an array containing the old and new value. This can then be used like this;

after_commit :do_something, if: proc { |object| object.previous_changes.include?('field') }

This will work the same as using field_changed? but will also ensure the changes have been committed to the database.