Rails 8 provides a new way of doing things after the current transaction, without defining a model "global" after_commit callback.
def do_something
update_column(:foo, "bar")
send_email(foo: "bar")
end
The above code is brittle if it's called within a failing transaction:
ActiveRecord::Base.transaction do
user.do_something
raise "oh no, my transaction failed"
end
In the case above, the database update is lost, but the email is sent out. Also, the database transaction is long (this is bad for performance in general) because it waits for send_email, which depending on its implementation makes slow network calls.
You can now rewrite this with current_transaction to without having to define a global after commit callback:
def do_something
update_column(:foo, "bar")
ActiveRecord::Base.current_transaction.after_commit { send_email(foo: "bar") }
ActiveRecord::Base.current_transaction.after_rollback { Rails.logger.warn("rollback") } # after_rollback is also supported
end
Posted by Niklas Hä. to makandra dev (2026-07-07 11:44)