Following code was tested with edge rails (rails4) .
In a RubyonRails application we save records often. It is one of the most used methods in ActiveRecord. In the blog we are going to take a look at the life cycle of save operation.
A typical model looks like this.
Now lets look at ActiveRecord::Base class in its entirety.
Base class extends and includes a lot of modules. Here we are going to look at the four modules that have method def save .
Module Persistence defines save method like this
Now lets see method create_or_update .
So save method invokes create_or_update and create_or_update method either creates a record or updates a record. Dead simple.
In module Validations the save method is defined as
In this case the save method simply invokes a call to perform_validations .
Module AttributeMethods includes a bunch of modules like this
Here we want to look at Dirty module which has save method defined as following.
Since this module is all about tracking if a record is dirty or not, the save method tracks the changed values.
In module Transactions the save method is defined as
The method rollback_active_record_state! is defined as
And the method with_transaction_returning_status is defined as
Together methods rollback_active_record_state! and with_transaction_returning_status ensure that all the operations happening inside save is happening in a single transaction.
Why save method needs to be in a transaction .
A model can define a number of callbacks including after_save and before_save. All those callbacks are operated within a transaction. It means if an after_save callback operation raises an exception then the save operation is rolled back.
Not only that a number of associations like has_many and belongs_to use callbacks to handle association manipulation. In order to ensure the integrity of the operation the save operation is wrapped in a transaction .
reverse order of operation
In the Base class the modules are included in the following order.
All the four modules have save method. The way ruby works the last module to be included gets to act of the method first. So the order in which save method gets execute is Transactions, AttributeMethods, Validations and Persistence .
To get a visual feel, I added a puts inside each of the save methods. Here is the result.