Actually this is exactly how Nested Transactions was designed for. I quote from oracle docs:
A nested transaction is used to provide a transactional guarantee for a subset of operations performed within the scope of a larger transaction. Doing this allows you to commit and abort the subset of
operations independently of the larger transaction.
So, a child transaction in a regular nested transaction has no say regarding how him or the other children or parent (larger transaction) could behave, other than changing mutual data or failing for an exception.
But you can grant him (child transaction) a very limited voting chance on his destiny by utilizing the sub-transaction
feature as stated at rails docs by passing requires_new: true
User.transaction do
User.create(username: 'Kotori')
User.transaction(requires_new: true) do
User.create(username: 'Nemu')
raise ActiveRecord::Rollback
end
end
Which as the docs say: only creates 'Kotori'. since the powerful 'Nemu' child chose to die silently.
More details about Nested transaction rules (oracle docs)
Update:
To better understand why rails nested transactions
works this way, you need to know a bit more about how nested transactions works in DB level, I quote from rails api docs:
Most databases don’t support true nested transactions ...In order to
get around this problem, #transaction will emulate the effect of
nested transactions, by using savepoints:
http://dev.mysql.com/doc/refman/5.0/en/savepoint.html
Ok, then the docs describes the behavior of a nested transaction
in the two mentioned cases as follows:
In case of a nested call, #transaction will behave as follows:
The block will be run without doing anything. All database statements that happen within the block are effectively appended to the already open database transaction.
However, if :requires_new is set, the block will be wrapped in a database savepoint acting as a sub-transaction.
I imagine careful, only imagine that:
option(1) (without requires_new) is there in case you used a DBMS that fully supports nested transactions
or you are happy with the "fake" behavior of nested_attributes
while option(2) is to support the savepoint
workaround if you don't.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…