|
| 1 | +# Ensure Record Saved With after_commit Callback |
| 2 | + |
| 3 | +In my experience, some of the more common `ActiveRecord` callbacks are ones |
| 4 | +like `before_save` or `after_update`. While working with some code, where I |
| 5 | +needed to send a notification when a certain value was updated, I learned that |
| 6 | +something like `after_update` wasn't sufficient. |
| 7 | + |
| 8 | +If my record is updated within a transaction, the `after_update` will get |
| 9 | +triggered even though the changes could later get rolled back resulting in me |
| 10 | +erroneously sending the notification. |
| 11 | + |
| 12 | +```ruby |
| 13 | +ActiveRecord::Base.transaction do |
| 14 | + user.update(interesting_value: 123) |
| 15 | + |
| 16 | + do_something # <-- rollback could happen here! |
| 17 | +end |
| 18 | +``` |
| 19 | + |
| 20 | +To ensure I'm not over-eager with my notifications, I should instead use |
| 21 | +[`after_commit`](https://api.rubyonrails.org/v7.0.5/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit) |
| 22 | +which only gets called after the changes have been committed to the database. |
| 23 | + |
| 24 | +```ruby |
| 25 | +class User < ApplicationRecord |
| 26 | + after_commit :send_notification, |
| 27 | + on: [:create, :update], |
| 28 | + if: :interesting_value_was_changed? |
| 29 | + |
| 30 | + # rest of class... |
| 31 | + |
| 32 | + private |
| 33 | + |
| 34 | + def send_notification |
| 35 | + # logic... |
| 36 | + end |
| 37 | + |
| 38 | + def interesting_value_was_changed? |
| 39 | + # logic... |
| 40 | + end |
| 41 | +end |
| 42 | +``` |
| 43 | + |
| 44 | +On either `create` or `update` if my condition is met, then after the _commit_ |
| 45 | +goes through, the `#send_notification` method will be triggered. |
0 commit comments