I have learned a lot by reading the API docs at Ruby on Rails Active Record Transaction .
Transactions are protective blocks where SQL statements are only permanent if they can all succeed as one atomic action.
The classic example is a transfer between two accounts where you can only have a deposit if the withdrawal succeeded and vice versa.
Transactions enforce the integrity of the database and guard the data against program errors or database break-downs. So basically you should use transaction blocks whenever you have a number of statements that must be executed together or not at all.
Examples
1. Withdrawal and Deposit:
ActiveRecord::Base.transaction do
david.withdrawal(100)
mary.deposit(100)
end
So, while running the withdrawal method of the user model, if an error comes then the next method of user deposit is not called.
Similarly, if the withdrawal of David is done but an error comes in the deposit method of Mary then changes occurred during David’s withdrawal method will be rollback so the money will not be transferred at all.
2. Object Duplication:
I normally use Active Record Transactions when I am about to duplicate an instance that also has a relation of has_many
with other model instances.
class Post < ApplicationRecord
...
def duplicate!
ActiveRecord::Base.transaction do
post_dup = self.dup
post_dup.save!
comments.find_each do |comment|
comment_dup = comment.dup
comment_dup.post_id = post_dup.id
comment_dup.save!
end
end
end
end
So, the duplicated post doesn’t get saved until unless all the comments of the post are duplicated and save with duplicate post id.
Callbacks of Active Record Transaction
Active Record Transactions have two callbacks after_commit
, and after_rollback
.
after_commit
is called when the transaction is completed successfully.
after_rollback
is called when the transaction is unsuccessful.
Models are children of Application Record:
Transactions are per-database connection, not per-model.
As the transaction is the part of ActiveRecord::Base
so all models can access transactions using class or instance. For Example, below are all valid snippets:
Account.transaction do
balance.save!
account.save!
end
balance.transaction do
balance.save!
account.save!
end
Rails 6 multiple database connection issues:
A transaction acts on a single database connection. If you have multiple class-specific databases, the transaction will not protect interaction among them. One workaround is to begin a transaction on each class whose models you alter:
Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end
This is a poor solution, but fully distributed transactions are beyond the scope of Active Record.
Top comments (0)