Serialized Attributes in ActiveRecord 3.2
Rails has had serialized attributes for a while, and every time I try to do something fancy with them, I have to rediscover how they work.
I have used composed_of
to do some of these things in the past, so take a look at it if
serialize
isn’t quite what you’re looking for.
The basics
To get started with serialize, add a text
column to your table,
and add the serialize directive to your model.
If you choose the last option, what aspects of serialization can you control?
Default serialization with YAML
By default, your attribute will be serialized as YAML. Let’s say you define MyField like this:
It will be serialized like this:
--- !ruby/object:MyField {}
It will deserialize back to a MyField
instance.
Custom serialization
You can customize the serialization in a couple of different ways.
One way is to implement the instance method to_yaml
. I wouldn’t
do this, because you’ll need to do it in a way that Yaml.load
can
use to create an instance of your class.
The other way to do it is to add dump
and load
class methods to
your class. For example:
Dump converts your object to a string, and load converts a string into an instance of your class. Here’s an example of a custom formatting of attributes:
Now, let’s say you want to be able to assign a hash to the serialized object, maybe from a form. You can do that:
It’s worth noting that you’ll be without the instance of MyField at first.
>>> rec = MyModel.new
>>> rec.my_field.class
=> MyField
>>> rec.my_field = {}
>>> rec.my_field.class
=> Hash
>>> rec.save
=> true
>>> rec.my_field.class
=> MyField
So, another option is to override the setter on MyModel:
>>> rec = MyModel.new
>>> rec.my_field.class
=> MyField
>>> rec.my_field = {}
>>> rec.my_field.class
=> MyField
>>> rec.save
=> true
>>> rec.my_field.class
=> MyField
>>> rec.attributes = {:my_field => {}}
>>> rec.my_field.class
=> MyField