Master Sword
<%= 'Cause it's late and your mama don't know %>
Sword

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.

copy to clipboard
  1. class GiraffeSerializer < ActiveModel::Serializer
  2. attributes :name, :age, :name_and_age, :height, :children
  3.  
  4. def name_and_age
  5. "#{name} - #{age} year(s) old"
  6. end
  7. 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.

copy to clipboard
  1. class UserSerializer < ActiveModel::Serializer
  2. attributes :boolean_attribute
  3.  
  4. def boolean_attribute
  5. boolean_attribute.to_s
  6. end
  7. 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.)

copy to clipboard
  1. class UserSerializer < ActiveModel::Serializer
  2. attributes :email, :first_name, :last_name
  3.  
  4. def attributes
  5. hash = super
  6. hash["boolean_attribute"] = object.boolean_attribute.to_s
  7. hash
  8. end
  9. 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.