Skip to content

Commit

Permalink
Merge pull request #49885 from p8/guides/transaction-callbacks
Browse files Browse the repository at this point in the history
Clarify transaction callbacks section [ci-skip]
  • Loading branch information
p8 committed Nov 1, 2023
2 parents 44f914b + 5b6f422 commit 8e73e62
Showing 1 changed file with 18 additions and 18 deletions.
36 changes: 18 additions & 18 deletions guides/source/active_record_callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ You can declare as many callbacks as you want inside your callback classes.
Transaction Callbacks
---------------------

### Dealing With Consistency
### `after_commit` and `after_rollback`

There are two additional callbacks that are triggered by the completion of a database transaction: [`after_commit`][] and [`after_rollback`][]. These callbacks are very similar to the `after_save` callback except that they don't execute until after database changes have either been committed or rolled back. They are most useful when your Active Record models need to interact with external systems which are not part of the database transaction.

Expand Down Expand Up @@ -527,7 +527,23 @@ end

NOTE: The `:on` option specifies when a callback will be fired. If you don't supply the `:on` option the callback will fire for every action.

### Context Matters
WARNING. When a transaction completes, the `after_commit` or `after_rollback` callbacks are called for all models created, updated, or destroyed within that transaction. However, if an exception is raised within one of these callbacks, the exception will bubble up and any remaining `after_commit` or `after_rollback` methods will _not_ be executed. As such, if your callback code could raise an exception, you'll need to rescue it and handle it within the callback in order to allow other callbacks to run.

WARNING. The code executed within `after_commit` or `after_rollback` callbacks is itself not enclosed within a transaction.

WARNING. In the context of a single transaction, if you interact with multiple
loaded objects that represent the same record in the database, there's a crucial
behavior in the `after_commit` and `after_rollback` callbacks to note. These
callbacks are triggered only for the first object of the specific record that
undergoes a change within the transaction. Other loaded objects, despite
representing the same database record, will not have their respective
`after_commit` or `after_rollback` callbacks triggered. This nuanced behavior is
particularly impactful in scenarios where you expect independent callback
execution for each object associated with the same database record. It can
influence the flow and predictability of callback sequences, leading to potential
inconsistencies in application logic following the transaction.

### Aliases for `after_commit`

Since using the `after_commit` callback only on create, update, or delete is
common, there are aliases for those operations:
Expand All @@ -548,10 +564,6 @@ class PictureFile < ApplicationRecord
end
```

WARNING. When a transaction completes, the `after_commit` or `after_rollback` callbacks are called for all models created, updated, or destroyed within that transaction. However, if an exception is raised within one of these callbacks, the exception will bubble up and any remaining `after_commit` or `after_rollback` methods will _not_ be executed. As such, if your callback code could raise an exception, you'll need to rescue it and handle it within the callback in order to allow other callbacks to run.

WARNING. The code executed within `after_commit` or `after_rollback` callbacks is itself not enclosed within a transaction.

WARNING. Using both `after_create_commit` and `after_update_commit` with the same method name will only allow the last callback defined to take effect, as they both internally alias to `after_commit` which overrides previously defined callbacks with the same method name.

```ruby
Expand All @@ -573,18 +585,6 @@ irb> @user.save # updating @user
User was saved to database
```

WARNING. In the context of a single transaction, if you interact with multiple
loaded objects that represent the same record in the database, there's a crucial
behavior in the `after_commit` and `after_rollback` callbacks to note. These
callbacks are triggered only for the first object of the specific record that
undergoes a change within the transaction. Other loaded objects, despite
representing the same database record, will not have their respective
`after_commit` or `after_rollback` callbacks triggered. This nuanced behavior is
particularly impactful in scenarios where you expect independent callback
execution for each object associated with the same database record. It can
influence the flow and predictability of callback sequences, leading to potential
inconsistencies in application logic following the transaction.

### `after_save_commit`

There is also [`after_save_commit`][], which is an alias for using the `after_commit` callback for both create and update together:
Expand Down

0 comments on commit 8e73e62

Please sign in to comment.