To maintain the data integrity sometimes we need the changes to database to occur when all of the actions have successfully finished. One of the examples is funds transfer from one account to another. One account should be debited and another account should be credited with same amount. If any of these action fails the other action should revert to bring the database in previous state.
ActiveRecord::Transactions handles the complexity. When we pass a block to transaction all actions inside block are considered to be atomic. Either all action pass or the transaction will automatically be rolled back.
How to use transaction:
@acct1 = Account.find(1)
@acct2 = Account.find(2)
@acct1.balance -= transferred_amount
@acct2.balance += transferred_amount
We can start transaction with active record object or class:
Rails opens a transaction in database engine. If all actions are executed successfully, the database commits the data. If any exception occurs, rails will tell database to cancel the transaction and no changes will be committed. If anyhow the rails server dies, the transaction will timed out and no changes will be made to database.
In code above we used save! instead of save, because save! will raise exception if record is not saved. Transaction will pick exception and no changes will commit to database. save method return true/false.
Callbacks with transactions:
With transactions we can also use callbacks. after_commit callback fires when the transaction succeeds. after_rollbacks callback fires when the transaction fails.