Rails nested transactions
ActiveRecord::Rollback
does not propagate outside of the containing transaction block and so the parent transaction does not receive the exception nested inside the child.
To ensure a rollback is received by the parent transaction you must add the requires_new: true
option to the child transaction.
Check out this article and docs for more details.
So applying it to your case, you should have the user_service.rb
as follows:
class UserService def self.reduce_balance!(user, delta, attachmentable) ActiveRecord::Base.transaction(requires_new: true) do # code omitted end endend
Your issues stems from the way you use transactions.
Whenever you nest them you have to use requires_new: true
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction(requires_new: true) do endend
Its explained well in the doc.
Btw, it doesnt hurt to always use requires_new: true
.
Sidenote, you seem to use service objects and chain them, maybe this would interest you.