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.
Active Model Serializer consists of two components:
The serializer creates the relationship in the backend and then translates it to the frontend.
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.
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-
To achieve the intention of serialization
To mock (fill) data
Let’s get started with building our demo project for Active Model Serializer.
Create a new project by executing the below-mentioned command
Add below gems in your Gemfile
Install these newly added gems using this command
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).
$ 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.
After the model changes, migration is necessary. Run the below command.
We will now add routes for APIs-only methods. The routes can extend with other versioning.
# config/routes.rb
Rails.application.routes.draw do concern :api_base do resources :employees resources :managers end namespace :v1 do concerns :api_base end end
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.
Here’s the seeds.rb
# db/seeds.rb
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: "emp@gmail.com", dob: "17-01-1988", mobile: "8879544321", designation: "Senior Developer", salary: 35_000, manager: managers.sample ) end
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
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
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
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
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
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
The output for the request to fetch details of employees and managers APIs is as shown below.
// GET http://localhost:3000/v1/employees/1
{ "data":{ "id":1, "name":"employee", "email":"emp@gmail.com", "designation":"Senior Developer", "manager":{ "id":6, "name":"manager" } }, "message":[ "Employee profile fetched successfully" ], "status":200, "type":"Success" }
// GET http://localhost:3000/v1/managers/6
{ "data":{ "id":6, "name":"manager", "employees":[ { "id":1, "name":"employee", "email":"emp@gmail.com", "designation":"Senior Developer" }, { "id":33, "name":"employee", "email":"emp@gmail.com", "designation":"Senior Developer" }, { "id":39, "name":"employee", "email":"emp@gmail.com", "designation":"Senior Developer" } ] }, "message":[ "Manager profile fetched successfully" ], "status":200, "type":"Success" }
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:
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.
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.