Nested transactions with Rails

In Ruby on Rails, nested transactions are owned by the most outer transaction. It means that raising ActiveRecord::Rollback error in the code below, will not prevent it from creating 2 users in the database:

User.transaction do
  User.create(username: 'Kotori')
  User.transaction do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

It happens because exceptions captured within second transaction blocks are not visible to the first transaction. To make a nested transaction to behave like you would normally expect, you need to pass requires_new: true parameter:

User.transaction do
  User.create(username: 'Kotori')
  User.transaction(requires_new: true) do
    User.create(username: 'Nemu')
    raise ActiveRecord::Rollback
  end
end

ActiveRecord emulates nested transactions via savepoints (supported by MySQL and PostgreSQL). More info here.

Savepoint vs nested transaction

On the first sight savepoint might look identical to a nested transaction, but there is a main difference between them: rolling back outer transaction will revert changes from all nested savepoints, meanwhile true nested transaction could still be committed.