diff --git a/README.md b/README.md index b390aad..c965f87 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1316 TILs and counting..._ +_1317 TILs and counting..._ --- @@ -807,6 +807,7 @@ _1316 TILs and counting..._ - [Disambiguate Where In A Joined Relation](rails/disambiguate-where-in-a-joined-relation.md) - [Ensure A Rake Task Cannot Write Data](rails/ensure-a-rake-task-cannot-write-data.md) - [Ensure Migrations Use The Latest Schema](rails/ensure-migrations-use-the-latest-schema.md) +- [Ensure Record Saved With after_commit Callback](rails/ensure-record-saved-with-after-commit-callback.md) - [Find Or Create A Record With FactoryBot](rails/find-or-create-a-record-with-factory-bot.md) - [Find Records With Multiple Associated Records](rails/find-records-with-multiple-associated-records.md) - [Force All Users To Sign Out](rails/force-all-users-to-sign-out.md) diff --git a/rails/ensure-record-saved-with-after-commit-callback.md b/rails/ensure-record-saved-with-after-commit-callback.md new file mode 100644 index 0000000..f31648e --- /dev/null +++ b/rails/ensure-record-saved-with-after-commit-callback.md @@ -0,0 +1,45 @@ +# Ensure Record Saved With after_commit Callback + +In my experience, some of the more common `ActiveRecord` callbacks are ones +like `before_save` or `after_update`. While working with some code, where I +needed to send a notification when a certain value was updated, I learned that +something like `after_update` wasn't sufficient. + +If my record is updated within a transaction, the `after_update` will get +triggered even though the changes could later get rolled back resulting in me +erroneously sending the notification. + +```ruby +ActiveRecord::Base.transaction do + user.update(interesting_value: 123) + + do_something # <-- rollback could happen here! +end +``` + +To ensure I'm not over-eager with my notifications, I should instead use +[`after_commit`](https://api.rubyonrails.org/v7.0.5/classes/ActiveRecord/Transactions/ClassMethods.html#method-i-after_commit) +which only gets called after the changes have been committed to the database. + +```ruby +class User < ApplicationRecord + after_commit :send_notification, + on: [:create, :update], + if: :interesting_value_was_changed? + + # rest of class... + + private + + def send_notification + # logic... + end + + def interesting_value_was_changed? + # logic... + end +end +``` + +On either `create` or `update` if my condition is met, then after the _commit_ +goes through, the `#send_notification` method will be triggered.