Serialized Attributes in Rails
Sunday, October 11th, 2009 · 0 comments
Over the last couple days I've been playing around with the Marshal library in Ruby for the serialization of objects. The idea came to me when I was snooping around Mint's database structure. It stores application settings and certain statistics in serialized format. I experimented for a while in pure Ruby, and after having reasonably success, moved to Rails.
Now for some great advice, always search first! I ended up implementing my Ruby Marshal technique in Rails, only to later find out about Rails's serialize() method. While it uses YAML in place of Marshal to serialize the data, it was a perfect solution.
# serialize(attr_name, class_name = Object)
If you have an attribute that needs to be saved to the database as an object,
and retrieved as the same object, then specify the name of that attribute
using this method and it will be handled automatically. The serialization is
done through YAML. If class_name is specified, the serialized object must be
of that class on retrieval or SerializationTypeMismatch will be raised.
# Parameters
attr_name - The field name that should be serialized.
class_name - Optional, class name that the object type should be equal to.
# Example
class User
serialize :preferences
end
This worked great, except for one part. It was difficult to write forms to create/update the serialized attributes, since the application had no idea what fields I wanted to store. So after a bit of playing, I came up with some getter/setter methods.
class Article < Content
serialize :data
def title
data[:title]
end
def title=(value)
self.data[:title] = value
end
end
That solved the form.text_field :title problem, but it still didn't work because when I created a new Article, there was no such thing as data[:title]. The solution was to initialize the :data attribute when creating the object. Here's an example:
class ArticlesController < ApplicationController::Base
def new
@article = Article.new(:data => { :title => nil })
end
def create
@article = Article.new(:data => { :title => params[:article][:title] })
# Code to save record...
end
end
That's it. It's not the cleanest solution I think, but it did the job just fine for the application I was writing.
