Active Model Serializers(AMS) let you customize and create custom object-oriented JSON output of Rails API responses. This way, you can define the serialization for the attribute of your model and take control over the data and include nested data from associated models. AMS uses adapters and intermediaries to convert the data into JSON format and improve API performance by making a single request to the backend.
The Active Model Serializer consists of two major components: Serializer and Adapters. Serializer describes which attributes should be serialized so that the relationship can be defined in the backend and can be translated for the frontend. Adapters define how objects, including their attributes and relationships, are converted into a format suitable for storage or transmission. Additionally, by selectively including required attributes or data, you can improve API performance.
In this blog, we are going to demonstrate the implementation of AMS in an organized way.
Implement Active Model Serializer with Rails API
An API should be well-structured and have clear endpoints and resource naming conventions to ensure usability. And implementation of serialization in Rails APIs notably improved performance for JSON responses. Rails already supports JSON rendering, but AMS allows you to customize the output, enabling more efficient and flexible responses with a single backend request. This customization allows you to define data, reduce redundancy, and even handle complex nested relationships cleanly. This customization allows each resource to be represented as a class inherited from AMS.
Let’s get started with the Movies and Reviews API project idea, a lightweight replication of popular review platforms like Rotten Tomatoes. This will allow users to fetch a list of movies, their details, and associated user reviews.
Here’s how you can implement AMS in an organized way:
1. Set Up Your Rails API Project
The first requirement is to create a Rails project in API only mode so that the default Rails stack can be trimmed down for building an API.
rails new movie_review_api --api
2. Add Required Gemfile
Next, add the Gemfile like Faker, which gives you all the serialization tools for generating mock data.
Update your Gemfile to include:
i.
gem 'active_model_serializers'
gem 'faker', group: [:development, :test]
ii. Install the gems:
bundle install
3. Create Models and Set Up Associations
Think about the resources your API will expose. We will set up your models- Movie and Review, with the appropriate fields and relationships. A movie can have many reviews. A review belongs to a single movie.
Run the following generators:
rails g model Movie title description genre release_year:integer
rails g model Review reviewer_name comment rating:integer movie:references
Establish relationships in the models:
# app/models/movie.rb
class Movie < ApplicationRecord
has_many :reviews, dependent: :destroy
end
# app/models/review.rb
class Review < ApplicationRecord
belongs_to :movie
end
4. Database Migration
Once your models and associations are defined, don’t forget to run your database migrations.
rails db:migrate
5. Seed the Database with Mock Data
It is always helpful to work with realistic data when developing an API. We will use Faker to create some sample data for movies and reviews, which will make testing endpoints easier and help observe how serializers behave.
# db/seeds.rb
10.times do
movie = Movie.create!(
title: Faker::Movie.title,
description: Faker::Lorem.paragraph,
genre: Faker::Book.genre,
release_year: rand(1980..2023)
)
rand(2..5).times do
movie.reviews.create!(
reviewer_name: Faker::Name.name,
comment: Faker::Lorem.sentence,
rating: rand(1..10)
)
end
end
Seed the database:
rails db:seed
6. Configure Routes
We’ll use versioned routes for scalability.
# config/routes.rb
Rails.application.routes.draw do
namespace :v1 do
resources :movies, only: [:index, :show]
resources :reviews, only: [:index, :show]
end
end
7. Create Serializers
Now we are creating a corresponding serializer for the data of the specific model we want to customize the JSON output for. These serializers determine what attributes are included when the model is rendered as JSON.
# app/serializers/v1/movie_serializer.rb
module V1
class MovieSerializer < ActiveModel::Serializer
attributes :id, :title, :genre, :release_year, :average_rating, :review_count
has_many :reviews
def average_rating
object.reviews.average(:rating)&.round(2)
end
def review_count
object.reviews.count
end
end
end
# app/serializers/v1/review_serializer.rb
module V1
class ReviewSerializer < ActiveModel::Serializer
attributes :id, :reviewer_name, :comment, :rating
belongs_to :movie
end
end
8. Customize Your Controllers to Use Serializers
You can explicitly specify which serializer to use when rendering JSON using AMS.
# app/controllers/v1/movies_controller.rb
module V1
class MoviesController < ApplicationController
def index
movies = Movie.includes(:reviews).all
render json: movies, each_serializer: V1::MovieSerializer
end
def show
movie = Movie.find(params[:id])
render json: movie, serializer: V1::MovieSerializer
end
end
end
# app/controllers/v1/reviews_controller.rb
module V1
class ReviewsController < ApplicationController
def index
reviews = Review.includes(:movie).all
render json: reviews, each_serializer: V1::ReviewSerializer
end
def show
review = Review.find(params[:id])
render json: review, serializer: V1::ReviewSerializer
end
end
end
9. Example API Responses
GET /v1/movies/1
{
"id": 1,
"title": "The Shawshank Redemption",
"genre": "Drama",
"release_year": 1994,
"average_rating": 8.7,
"review_count": 4,
"reviews": [
{
"id": 12,
"reviewer_name": "Jane Doe",
"comment": "A timeless classic.",
"rating": 9
},
{
"id": 13,
"reviewer_name": "John Smith",
"comment": "Brilliant storytelling.",
"rating": 10
}
]
}
GET /v1/reviews/13
JSON
{
"id": 13,
"reviewer_name": "John Smith",
"comment": "Brilliant storytelling.",
"rating": 10,
"movie": {
"id": 1,
"title": "The Shawshank Redemption"
}
}
10. Versioning Your API
Versioning is important for maintaining backward compatibility as your API evolves. With AMS, you can simply namespace your controllers and serializers without breaking existing clients. You can create a new version folder (v2) for controllers and serializers.
11. Test the API Endpoints
Now that everything is done, you can use tools such as Postman to test your API endpoints on the Rails server. You should see clean, structured JSON responses that match your serializer definitions.
This is a good time to check:
The correct attributes are exposed.
Nested relationships are serialized as expected.
No sensitive information is being leaked.
Conclusion
Using Active Model Serializers (AMS) in a Rails API project improves the structure and speed of your JSON responses. Serializers help eliminate redundancy, enable clean nested relationships, to maintain consistent formatting across endpoints. It is ideal for projects of any scale, from simple apps to enterprise systems.
At Atharva System, we leverage AMS to build robust, maintainable, and scalable APIs. We combine AMS with best practices. This way, our APIs provide optimized, secure, and frontend-friendly responses for our Rails projects. Our expert team can manage complex model relationships, customize outputs, and boost API performance while reducing unnecessary data exposure.
Want to improve your API development workflow with Active Model Serializers?
Partner with Atharva System—your trusted Ruby on Rails development company—to build efficient, scalable, and performance-optimized APIs tailored to your project needs.