Customize Named Model Attributes with ActiveModel::Serializers
If you’ve used ActiveModel::Serializers to serialize your Ruby objects into JSON (presumably in a Rails application), you’re familiar with the tools that Yehuda Katz’ brainchild affords us. When using Rails to build JSON APIs for front-end JavaScript applications (or general consumption), we can rely on ActiveModel::Serializers for serializing not only database-backed model attributes, but also custom attributes and associated records.
class GiraffeSerializer < ActiveModel::Serializer
attributes :name, :age, :name_and_age, :height, :children
def name_and_age
"#{name} - #{age} year(s) old"
end
end
In most applications, these features will suffice. However, when working on an AngularJS front-end recently, we sought to serialize a boolean model attribute as a string. The “why” is somewhat irrelevant, but it had something to do with a quirk in binding model attributes to form inputs in a directive. In any case, the task seemed simple. Perhaps something like the following would work.
class UserSerializer < ActiveModel::Serializer
attributes :boolean_attribute
def boolean_attribute
boolean_attribute.to_s
end
end
As you can probably see already, this isn’t a solution. The nasty feeling we permit when writing this code is accompanied by an ugly stack trace error. Onto the next one.
Luckily, “the next one” just so happens to be an ideal solution. If you seek to modify a model attribute (while retaining its name in serialization), you can do so by overriding the attributes method. (This is, in fact, documented.)
class UserSerializer < ActiveModel::Serializer
attributes :email, :first_name, :last_name
def attributes
hash = super
hash["boolean_attribute"] = object.boolean_attribute.to_s
hash
end
end
Notice that we leave boolean_attribute
from the inital attributes
call.
This is because we’ve specified it explicitly in our custom attributes
method.
And with this, we’ve serialized our boolean attribute as a string without
altering its name. (Note that object
refers to the object being serialized.)
If you haven’t had the chance to dig into ActiveModel::Serializers yet, I recommend that you give it a go. This whole “JSON API in Rails” thing is pretty fun.