Free tools Windows power users keep installed
One-click scans. No signup required.
A Rails rollback reverses database work in that transaction; it does not automatically undo a request another service has accepted or an email already sent. Jobs are the exception that needs closer inspection: whether an enqueue rolls back depends on the queue backend, database setup, and whether enqueueing waits for commit.
What a rollback does—and does not—undo
A database transaction governs database work on its connection. It is not a distributed transaction spanning your database, an API provider, an email system, and a job queue. If Rails sends a request or message before the database transaction finishes, a later rollback cannot recall that external action.
Rails describes transaction callbacks as useful when models interact with systems outside the database transaction. The key question is therefore not just “Did the transaction roll back?” but “Which steps had already happened, and where were they stored?”
Trace the incident as separate events
Reconstruct the sequence rather than treating the whole operation as one unit:
#1 Best Overall
- Database changes: Identify the transaction that committed or rolled back and the records it affected.
- External request or synchronous mail: Find whether it ran inline, in a callback, or elsewhere; inspect request logs, provider responses, and message IDs.
- Queue insertion: For a job or
deliver_later, determine whether the job was actually enqueued and where the queue stores it. - Job execution: Check whether a worker started the job before or after the rollback, and whether it could see the database state it needed.
Correlate Rails logs with the external provider’s records. Rails transaction instrumentation can expose outcomes such as commit or rollback, which helps establish the database part of the timeline; it does not by itself prove what a remote service did.
API calls: a rollback cannot retract an accepted request
If an API call happened before rollback, the remote service may have processed it even though Rails later discarded its own database changes. A timeout or missing response can leave the outcome uncertain, too; consult provider records or request logs rather than inferring success or failure from the database state.
Rank #2
When an API action should happen only if the database work succeeds, trigger it after commit. If a remote action can be repeated, use a provider-supported idempotency key where available. If the remote state must be corrected after a local rollback, that requires a deliberate compensating action; Rails does not provide a distributed rollback.
Emails: distinguish immediate delivery from queued delivery
deliver_now
deliver_now sends synchronously. Once the mail provider has accepted the message, a later database rollback cannot unsend it. Avoid sending before the transaction outcome is known when the message must reflect committed state.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #3
deliver_later
deliver_later enqueues an Action Mailer delivery job through Active Job. Its behavior follows the queueing configuration: separate the question of whether the job entered the queue from whether a worker executed it. Check the queue and worker logs, as well as the Active Job setting for deferring enqueueing until commit.
Jobs: queue configuration determines what rollback means
There is no universal rule that a job enqueue is part of every Rails transaction. The Active Job guide explains that with Solid Queue sharing the application’s database, enqueueing can participate in the Active Record transaction: rollback means the job is not enqueued, and an enqueue failure can prevent the transaction from committing. Rails 8 configures Solid Queue on a separate database by default, so do not assume that same-database behavior applies to your deployment. See the Active Job guide and verify the environment involved in the incident.
Rank #4
For a portable “enqueue only after successful commit” approach, configure enqueue_after_transaction_commit = true on the job or globally, or enqueue from an after_commit callback. Without deferred enqueueing, a job may enter a separate queue despite a later database rollback. A worker may also run before another database connection can see the transaction’s uncommitted row.
Use transaction callbacks for effects tied to commit or rollback
after_commit for work that needs durable data
Put a side effect that must follow a successful commit in after_commit. Rails’ callback guide illustrates why: deleting a file before the database change is safely committed can leave the file and database out of sync if later work raises and causes rollback. Moving the deletion into after_commit avoids acting on a change that never became durable.
Best Value
The callback runs after the database change has been persisted, so its code is not part of that transaction. If an after_commit callback raises, the commit remains; Rails also notes that the exception can bubble up and prevent remaining transaction callbacks from running. Handle errors and make them observable—for example, through logging and an appropriate retry or recovery path—rather than treating callback success as guaranteed.
after_rollback for rollback-specific cleanup
Use after_rollback for cleanup or other work that should happen when the transaction rolls back. It is not a mechanism for undoing an API call or email already accepted by another system; that requires a separate compensating action.
Transaction-level callbacks
For work that is not naturally tied to one model, Rails also documents callbacks on transaction objects and ActiveRecord.after_all_transactions_commit. The latter waits for the outermost currently open transaction and does not run if an open transaction rolls back. See Rails’ Active Record callbacks guide for the callback behavior and examples.
Check nested transactions before interpreting the rollback
An ordinary nested transaction call generally joins its parent; it does not create an independent database transaction. With requires_new: true, Rails can use a savepoint-backed nested transaction. A rollback to that savepoint is not necessarily a rollback of the outer transaction, so identify which scope rolled back and whether the outer transaction later committed. Rails documents these behaviors in its transaction API documentation.
Incident checklist
- Confirm the Rails version, Active Job adapter, and actual queue backend in the affected environment.
- Locate the side effect: inline in the transaction, in a pre-commit callback, in
after_commit, or inside a job. - For a job or
deliver_later, inspectenqueue_after_transaction_commit, whether Solid Queue and application records share a database, and queue and worker logs. - Trace the exception path and nested transaction scopes, including any use of
requires_new: true. - Correlate Rails transaction logs with API responses, provider message IDs, or other external records.
- Make retries safe. Repeated job execution or API requests can duplicate effects unless the job and any remote operation are designed to tolerate retries. Active Job does not retry failed jobs unless retry behavior is configured.
The practical conclusion is specific to each event: the rollback establishes what happened to the database transaction, not automatically what happened to an API, mail provider, queue, or worker.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

