Everything you need to know about the Active Model Serializer gem

Last updated on October 10, 2022

As Rubyists, we all know that ruby gems can make coding a little bit easier and this one is no different. Active Model Serializer is by far my favorite gem. In this post, I’ll show you why this gem is a must-have to develop better APIs and if you already use it but want to have a better understanding of how it works, this post is also for you.

What is the Active Model Serializer gem for and why do I need to serialize my data?

Active Model Serializer is a Ruby gem that serializes data. A serializer allows you to decide which attributes and relationships will be rendered on your API which makes it possible to customize JSON data.

Why would you want to customize or modify your JSON response?

By default, rails API renders all data and this can be a problem. There is data you probably won’t need to render and another common problem is an increase in data over time, which can lead to slow page loading time. As you know, slowness accumulates over time! Take a look at this JSON response. All relationships and attributes are being rendered.

[
  {
    "id": 1,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "created_at": "2022-08-23T14:14:44.313Z",
    "updated_at": "2022-08-23T14:14:44.313Z"
  },
  {
    "id": 2,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Tent of Miracles",
    "year": 1985,
    "created_at": "2022-08-23T14:14:44.323Z",
    "updated_at": "2022-08-23T14:14:44.323Z"
  },
  {
    "id": 3,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "created_at": "2022-08-23T14:14:44.342Z",
    "updated_at": "2022-08-23T14:14:44.342Z"
  }
]

How does the Active Model Serializer gem work?

ActiveModelSerializers is all about convention over configuration. This is a software design paradigm that makes a developer’s life easier because we don’t have to take too many decisions. As long as you follow certain conventions you don’t need to add additional configuration.

This gem is composed of serializers (responsible for which attributes and relationships are serialized) and adapters (how these attributes and relationships will be rendered). As I said before, the gem customizes which and how attributes and relationships should appear and does this through serializers and adapters, respectively.

Let’s customize our JSON response

Let’s start our rails API application by running

rails new bookstore --api
bundle install

Great! Now we can create our models

rails g model author
rails g model illustrator
rails g model book author:references illustrator:references

Don’t forget to set the routes.rb

Rails.application.routes.draw do
 resources :books
 resources :authors, only: [:index, :show]
 resources :illustrators, only: [:index, :show]
end

And our controllers with their relationships:

rails g controller authors
class AuthorsController < ApplicationController
 def index
   render json: Author.all
  end

 def show
   render json: Author.find(params[:id])
 end

 private

 def author_params
   params.require(:author).permit(:name)
 end
end
rails g controller illustrators
class IllustratorsController < ApplicationController
 def index
   render json: Illustrator.all
  end

 def show
   render json: Illustrator.find(params[:id])
 end

 private

 def illustrator_params
   params.require(:illustrator).permit(:name)
 end
end
rails g controller books
class BooksController < ApplicationController
 def index
   render json: Book.all
  end

 def show
   render json: Book.find(params[:id])
 end

 private

 def book_params
   params.require(:book).permit(:name, :year, :author_id)
 end
end
rails db:create db:migrate

Let’s populate our database in seeds.rb with test data:

jorge_amado = Author.create(name: "Jorge Amado")
floriano_teixeira = Illustrator.create(name: 'Floriano Teixeira')
dona_flor = Book.create({ name: 'Dona Flor and Her Two Husbands', year: 1966, author_id: jorge_amado.id, illustrator_id: floriano_teixeira.id })
tent = Book.create({ name: 'Tent of Miracles', year: 1985, author_id: jorge_amado.id, illustrator_id: floriano_teixeira.id })
gabriela = Book.create({ name: 'Gabriela, Clove and Cinnamon', year: 1958, author_id: jorge_amado.id, illustrator_id: floriano_teixeira.id })

Ok, now with everything set up, let’s see how the data is being rendered for Author, Book, and Illustrator

rails s

http://localhost:3000/books

[
  {
    "id": 1,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "created_at": "2022-08-23T14:14:44.313Z",
    "updated_at": "2022-08-23T14:14:44.313Z"
  },
  {
    "id": 2,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Tent of Miracles",
    "year": 1985,
    "created_at": "2022-08-23T14:14:44.323Z",
    "updated_at": "2022-08-23T14:14:44.323Z"
  },
  {
    "id": 3,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "created_at": "2022-08-23T14:14:44.342Z",
    "updated_at": "2022-08-23T14:14:44.342Z"
  }
]

http://localhost:3000/authors

[
  {
    "id": 1,
    "name": "Jorge Amado",
    "hometown": "Itabuna - Bahia - Brazil",
    "created_at": "2022-08-23T14:14:44.268Z",
    "updated_at": "2022-08-23T14:14:44.268Z"
  }
]

http://localhost:3000/illustrators

[
  {
    "id": 1,
    "name": "Floriano Teixeira",
    "hometown": "Cajapió - Maranhão - Brazil",
    "created_at": "2022-08-23T14:14:44.281Z",
    "updated_at": "2022-08-23T14:14:44.281Z"
  }
]

As you can see this is how the Rails API renders the JSON by default. What if we don’t need “created_at” or “updated_at”? And if we prefer to exhibit our author’s and illustrator’s names rather than author_id and illustrator_id? The Active Model Serializer gem comes to the rescue.

Add this to our Gemfile , then run bundle install

gem 'active_model_serializers', '~> 0.10.13'
bundle install

Head over to Rubygems for more info.

It’s serializer time!

Let’s create a serializer for the Books model.

rails g serializer Book

A new folder will be created in app > serializers > book_serializer.rb

class BookSerializer < ActiveModel::Serializer
 attributes :id
end

Go back to our http://localhost:3000/books and let’s check it out. This is a great example of convention over configuration. Once we run rails g serializer Book, it creates the serializer and renders it as it is.

[
  {
    "id": 1
  },
  {
    "id": 2
  },
  {
    "id": 3
  }
]

Now, we can add the attributes we would like to render, in this situation name and year. You can leave it out or place whatever attribute you need.

class BookSerializer < ActiveModel::Serializer
 attributes :id, :name, :year
end

And now we have:

[
  {
    "id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966
  },
  {
    "id": 2,
    "name": "Tent of Miracles",
    "year": 1985
  },
  {
    "id": 3,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958
  }
]

What about rendering each book’s author? In the book serializer, I let the relationship explicit by adding belongs_to: author

class BookSerializer < ActiveModel::Serializer
 attributes :id, :name, :year
 belongs_to: author
end

Just like magic, now we have all the Author’s attributes

[
  {
    "id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil",
      "created_at": "2022-08-23T14:14:44.268Z",
      "updated_at": "2022-08-23T14:14:44.268Z"
    }
  },
  {
    "id": 2,
    "name": "Tent of Miracles",
    "year": 1985,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil",
      "created_at": "2022-08-23T14:14:44.268Z",
      "updated_at": "2022-08-23T14:14:44.268Z"
    }
  },
  {
    "id": 3,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil",
      "created_at": "2022-08-23T14:14:44.268Z",
      "updated_at": "2022-08-23T14:14:44.268Z"
    }
  }
]

Let’s continue with our serialization by choosing which Author’s attributes we want to render. We can start by creating a serializer for the Author model.

rails g serializer author
class AuthorSerializer < ActiveModel::Serializer
 attributes :id
end

“created_at” and “updated_at” are no longer needed data, so we can leave them and place name and hometown

class AuthorSerializer < ActiveModel::Serializer
 attributes :id, :name, :hometown
end

Now we have all the data we need:

[
  {
    "id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 2,
    "name": "Tent of Miracles",
    "year": 1985,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 3,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  }
]

As simple as it is, we just customized our JSON response. Let’s compare with and without using the Active Model Serializer:

With serializers:

[
  {
    "id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 2,
    "name": "Tent of Miracles",
    "year": 1985,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 3,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  }
]

Without serializers:

[
  {
    "id": 1,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "created_at": "2022-08-23T14:14:44.313Z",
    "updated_at": "2022-08-23T14:14:44.313Z"
  },
  {
    "id": 2,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Tent of Miracles",
    "year": 1985,
    "created_at": "2022-08-23T14:14:44.323Z",
    "updated_at": "2022-08-23T14:14:44.323Z"
  },
  {
    "id": 3,
    "author_id": 1,
    "illustrator_id": 1,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "created_at": "2022-08-23T14:14:44.342Z",
    "updated_at": "2022-08-23T14:14:44.342Z"
  }
]

What about serializing methods?

Yes, the Active Model Serializer is a very powerful gem allowing you to even serialize methods. On our book’s table, there is a column called ‘year’ which refers to the book’s first year of publication. Let’s supposed I want to know how old is this book. In the book serializer, I created a very simple method called ‘book_age’ to calculate how old the book is and to make it render in our book’s endpoint, I just need to add this method as an attribute. Let’s check it out:

class BookSerializer < ActiveModel::Serializer
 attributes :id, :name, :year, :book_age
 belongs_to :author


 def book_age
   Date.today.year - (object.year)
 end
end

And here is the result:

[
  {
    "id": 1,
    "name": "Dona Flor and Her Two Husbands",
    "year": 1966,
    "book_age": 56,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 2,
    "name": "Tent of Miracles",
    "year": 1985,
    "book_age": 37,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  },
  {
    "id": 3,
    "name": "Gabriela, Clove and Cinnamon",
    "year": 1958,
    "book_age": 64,
    "author": {
      "id": 1,
      "name": "Jorge Amado",
      "hometown": "Itabuna - Bahia - Brazil"
    }
  }
]

Well, these are all small examples with just a few data points. Now imagine an application with lots of relationships and large models. With the Active Model Serializer gem, you can manage which attributes will be rendered and how they are rendered in a very simple way by using Active model serializers.

Invite us to your inbox.

Articles, guides and interviews about web development and career progression.

Max 1-2x times per month.