I have below code
ActiveRecord::Base.transaction do
begin
account.save
# outer statement
begin
user.save
# inner statement
rescue StandardError
raise ActiveRecord::Rollback
end
rescue StandardError
raise ActiveRecord::Rollback
end
end
If there is an exception in 'inner statement', only 'user' will be rollbacked, right? 'account' won't be rollbacked in that case, isn't it?
CodePudding user response:
In your code there is a single database transaction, and it is all-or-nothing. Rolling back a transaction will roll back all the changes made in that transaction, regardless of where you issue the rollback.
You can nest transactions as well, but be wary that by default transactions are squished together, so even if you add a second transaction inside first transaction:
ActiveRecord::Base.transaction do
begin
account.save
# outer statement
ActiveRecord::Base.transaction do
begin
user.save
# inner statement
rescue StandardError
raise ActiveRecord::Rollback
end
end
rescue StandardError
raise ActiveRecord::Rollback
end
end
This will still result in the single transaction, and rollback will cancel all the changes.
To ask for a real subtransaction, you need to add request_new: true
to the inner transaction:
ActiveRecord::Base.transaction do
begin
account.save
# outer statement
ActiveRecord::Base.transaction(require_new: true) do
begin
user.save
# inner statement
rescue StandardError
raise ActiveRecord::Rollback
end
end
rescue StandardError
raise ActiveRecord::Rollback
end
end
However, at the moment the only database supporting true nested transaction is MS-SQL. Rails at the moment handles this using save points - so don't be confused by the logs.