Quick Summary:

This blog covers insights into Active Model Serializers, their benefits, and their usage. In this tutorial, we will learn how to make serializers for Rails APIs and implement them efficiently so that they can be accommodated to versioning APIs too.

Table of Contents

What is Active Model Serializers?

Active Model Serializers provides a way of creating custom JSON in an object-oriented manner.
Active Model Serializer consists of two components:

  • Serializers: It describes which attributes & relationships to be serialized.
  • Adapters: It describes the way of serializing those attributes & relationships, i.e., how to serialize.

The serializer creates the relationship in the backend and then translates it to the frontend.

Importance and Usage of Active Model Serializers

Active Model Serializers offers a way to create custom JSON by representing each resource as a class inherited from Active Model Serializers. With the help of a serializer, we need to make a single request to the backend. With proper association done through serialization, the backend will fetch all the required data needed by request rather than requesting multiple times to multiple models.
The primary usage of Active Model Serializers is to create custom JSON responses. By default, Rails provides a way to render JSON, but we need a serializer if we want to customize it.

Active Model Serializers Tutorial: How to Implement Active Model Serializers with Rails API?

Here is the step-by-step guide to implementing Active Model Serializers with Rails API whose source code is available in the Github repository.

In this demo, we will be installing two dependencies-

  • active_model_serializers gem
  • To achieve the intention of serialization

    • faker gem
    • To mock (fill) data
      Let’s get started with building our demo project for Active Model Serializer.

      1. Create new project

      Create a new project by executing the below-mentioned command

      Copy Text
      rails new active-model-serializer --api

      2. Adding Gem

      Add below gems in your Gemfile

      • active_model_serializers
      • rack-cors
      • faker (development & test environment only)

      Install these newly added gems using this command

      Copy Text
      $ bundle install

      3. Data Modeling

      Firstly, we will create two models and connect them to One-to-Many relationships.
      We’ve built an Employee model having attributes (name, email, date_of_birth, mobile_no, designation, salary). Which belongs_to Manager model having the attribute (name).

      Copy Text
      $ rails g model Manager name
      $ rails g model Employee name email dob:date mobile
      designation salary:number manager:references

      The Manager has_many employees. At the same time, Employee belongs_to only one manager.

      4. Perform Migration

      After the model changes, migration is necessary. Run the below command.

      Copy Text
      $ rails db:migrate

      5. Configuration of Routes

      We will now add routes for APIs-only methods. The routes can extend with other versioning.
      # config/routes.rb

      Copy Text
      Rails.application.routes.draw do
        concern :api_base do
          resources :employees   
          resources :managers
        end
      
        namespace :v1 do
          concerns :api_base
        end
      end

      6. Pre-defined Data Added

      Declare data seed file to insert mock data for defined models. We can also enter data manually into the database, but it is easy with the seed file by running a single command.

      Copy Text
      $ rails db:seed

      Here’s the seeds.rb

      # db/seeds.rb

      Copy Text
      Employee.destroy_all
      Manager.destroy_all
      
      managers = (1..20).map do
        Manager.create!(
          name: "manager"
        )
      end
      
      employee = (1..50).map do
        Employee.create!(
          name: "employee",
          email: "[email protected]",
          dob: "17-01-1988",
          mobile: "8879544321",
          designation: "Senior Developer",
          salary: 35_000,
          manager: managers.sample
        )
      end

      7. Define Model Serializer

      We will define a serializer for each model indicating what data to be broadcasted over the network by serializing the model. The attribute we declared to be serialized can be further defined to explain what data to be passed for.
      You can see the below example for the model serializer.
      # app/serializers/v1/employee_serializer.rb

      Copy Text
      module V1
        class EmployeeSerializer < ActiveModel::Serializer
          attributes :id, :name, :email, :designation, :manager
      
          def manager
            {
              id: object.manager.id,
              name: object.manager.name
            }
          end
        end
      end

      # app/serializers/v1/manager_serializer.rb

      Copy Text
      module V1
        class ManagerSerializer < ActiveModel::Serializer
          attributes :id, :name, :employees
      
          def employees
            object.employees.map do |employee|
              {
                id: employee.id,
                name: employee.name,
                email: employee.email,
                designation: employee.designation
              }
            end
          end
        end
      end

      8. Define Controller

      It’s time to define the controller for respective models to serve serialized objects over API by explicitly defining serializers for individual models. Here, we will define which serializer will be used for passing data by JSON.
      You can see the below example for controllers.
      # app/controllers/v1/employees_controller.rb

      Copy Text
      module V1
        class EmployeesController < ApplicationController
      
          def index
            employees = Employee.all.includes(:manager)  
      // used includes method to prevent N-Query problem
            
            render json: {
              data: ActiveModelSerializers::SerializableResource.new(employees, each_serializer: EmployeeSerializer),
              message: ['Employee list fetched successfully'],
              status: 200,
              type: 'Success'
            }
          end
      
          def show
            employee = Employee.find(params[:id])
            
            render json: {
              data: ActiveModelSerializers::SerializableResource.new(employee, serializer: EmployeeSerializer),
              message: ['Employee profile fetched successfully'],
              status: 200,
              type: 'Success'
            }
          end
        end
      end

      # app/controllers/v1/managers_controller.rb

      Copy Text
      module V1
        class ManagersController < ApplicationController
          def index
            managers = Manager.all.includes(:employees)
            
            render json: {
              data: ActiveModelSerializers::SerializableResource.new(managers, each_serializer: ManagerSerializer),
              message: ['Manager list fetched successfully'],
              status: 200,
              type: 'Success'
            }
          end
      
          def show
            manager = Manager.find(params[:id])
            
            render json: {
              data: ActiveModelSerializers::SerializableResource.new(manager, serializer: ManagerSerializer),
              message: ['Manager profile fetched successfully'],
              status: 200,
              type: 'Success'
            }
          end
        end
      end

      9. End-point Response

      The output for the request to fetch details of employees and managers APIs is as shown below.
      // GET http://localhost:3000/v1/employees/1

      Copy Text
              {
      	  "data":{
      	    "id":1,
      	    "name":"employee",
      	    "email":"[email protected]",
      	    "designation":"Senior Developer",
      	    "manager":{
      	      "id":6,
      	      "name":"manager"
      	    }
      	  },
      	  "message":[
      	    "Employee profile fetched successfully"
      	  ],
                "status":200,
      	  "type":"Success"
      	}

      // GET http://localhost:3000/v1/managers/6

      Copy Text
             {
      	  "data":{
      	    "id":6,
      	    "name":"manager",
      	    "employees":[
      	      {
      	        "id":1,
      	        "name":"employee",
      	        "email":"[email protected]",
      	        "designation":"Senior Developer"
      	      },
      	      {
      	        "id":33,
      	        "name":"employee",
      	        "email":"[email protected]",
      	        "designation":"Senior Developer"
      	      },
      	      {
      	        "id":39,
      	        "name":"employee",
      	        "email":"[email protected]",
      	        "designation":"Senior Developer"
      	      }
      	    ]
      	  },
      	  "message":[
      	    "Manager profile fetched successfully"
      	  ],
      	  "status":200,
      	  "type":"Success"
      	}

      10. Versioning Controller & Serializer

      We can extend the API and serializers by versioning them.
      For creating another version of the controller, create it under the path app/controllers/v2/employees_controller.rb
      And for creating the serializer, create it under the path app/serializers/v2/employee_serializer.rb.
      Remember that the class you’re creating for versioned API should fall under module V2 (or whatever version you’re defining for).

      Here is the list of steps we performed to build serializer APIs:

      • Created new project using rails new active-model-serializer –api
      • Added required gems
      • Defined models
      • Migrated the schema
      • Configured routes for the API
      • Defined serializer for the respective model
      • Implemented business logic in the controller
      • Fetched data from API endpoints

      Alternative of Active Model Serializers

      • JSONAPI-RB– It is considered a highly performant and modular JSON:API. There’s a vibrant community around it that has produced this Ruby library consisting of four micro-libraries and two frameworks.
      • Fast JSON API– It is a lightning-fast JSON:API serializer for Ruby Objects. It is believed to be 25 times faster than Active Model Serializers.
      • Blueprinter– It is a high-speed, declarative, and API agnostic serializer that uses composable views for reducing duplication.

      Conclusion

      So, We hope you have a clear understanding of What is Active Model Serializers? Implementation, Usage, and Alternatives of Active Model Serializers in Rails 6. If you are looking for a helping hand in your Ruby on Rails project, then you’ve landed on the right page. Get in touch with us to hire ROR developer with the desired skillset at your ease and convenience.

Active Model Serializers Can Be A Game-Changer For Your Rails APIs

Contact us now and implement Active Model Serializers. It can help your API stand out from the rest and provide a better user experience.

Book a 30 min free call

Build Your Agile Team

Hire Skilled Developer From Us

[email protected]

Your Success Is Guaranteed !

We accelerate the release of digital product and guaranteed their success

We Use Slack, Jira & GitHub for Accurate Deployment and Effective Communication.

How Can We Help You?