Rails provides various methods to store objects in a standardized way.
One popular method is to use marshal
– the marshaling library
converts collections of Ruby objects into a byte stream,
allowing them to be stored outside the currently active script.
This is the general accepted method in the Ruby world.
However it is far less than efficient when storing ActiveRecord objects. It is unable to properly store binary attributes and is sometimes incompatible across Rails versions.
Before
Prior to this update, Rails developers had to use a hacked up solution to accurately serialize ActiveRecord objects. Let’s compare two popular methods used to do this.
First,
let’s look at #attributes
,
The first discrepancy is that though role
is an integer column in our database
the Rails enum translation is applied
and
the resultant JSON says role
is an admin though in reality it is an integer value.
Rails provides a useful method to extract attributes as they are in the database, attributes_before_type_cast
.
However even this does not provide a complete solution.
If a record is loaded from database,
attribute_before_type_cast
works – but if the attribute is changed by user,
the attribute method will not return mapped enum values.
After
Rails now has two related methods to overcome this.
The first is attribute_for_database
which consistently returns mapped value for enum.
This works per attribute.
With the latest update,
Rails 7 ActiveRecord attributes_for_database consistently serializes data.
Now,
it’s very easy to regenerate the record with instantiate
.