DEV Community

CluelessTurtle
CluelessTurtle

Posted on

Active Record Serializer

Databases and the data they have are very important for many successful web applications. One of the tasks a database has to handle is the distribution of data. This is very important because if a database sends to much data it can be very hard for any frontend framework to handle and manage it. In rails we handle the distribution of data with the ActiveModel::Serializer gem.

What is the Active Model Serializer gem?

To fully understand what the active model serializer gem is we first need to understand what a gem is. To put it simply a gem is an open source library that contains ruby code that is packaged together and once installed allows the programmer to utilize the code within it. This is great because it allows us to use pre-built code to help avoid doing repetitive tasks so we can focus our attention on the cool stuff.

So this brings us back to our original question what is the active model serializer gem? Simply put this gem helps to serialize our JSON data however we want. To serialize data means to pick which attributes and relationships we will be rendering on our API (Application Programming Interface) in other words customizing the data we return to our frontend. It is also worth mentioning that this gem does follow convention over configuration meaning that while using this gem there isn't much coding required on your part However, it is still important to understand what each method is doing since it won't be broken down for you.

How To Install

Installing this gem is very easy! The first thing we need to do is first add it to our gem file.

# Gemfile
gem 'active_model_serializers'
Enter fullscreen mode Exit fullscreen mode

Now we run bundle install to activate our gem and BOOM! we are ready to go!

How to use Active Model Serializer

The best way to understand how to use this gem is through example. So for this example let's say that we have a schema that looks like this

ActiveRecord::Schema.define(version: 2023_09_09_183405) do

  create_table "cars", force: :cascade do |t|
    t.integer "year"
    t.string "make"
    t.string "model"
    t.string "image"
    t.string "color"
    t.string "body_type"
    t.string "engine_size"
    t.string "drive_train"
    t.string "created_by"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end
end
Enter fullscreen mode Exit fullscreen mode

Wow that is alot of info on one car. So let's say all our frontend only needs to map through only the year, make, and model normally without a serializer we would have to let our car controller know what JSON to return like so.

class CarsController < ApplicationController
  def index
     cars = Car.all
     render json: cars.to_json(only: [:year, :make, :model]), 
     status: :ok
  end
end
Enter fullscreen mode Exit fullscreen mode

Well not to be rude but I think it's safe to say that to any developer this looks like an eyesore. The reason is that this can be very error-prone very quickly and on top of that it violates the separation of concerns. The controllers job is to interact with the model get whatever JSON data is requested and then pass that along to our frontend to present it to the user. It is not the controllers job to determine how the data should be returned rather this should be handled in our serializer.

With our serializer we first need to create a folder called Serializer and in that folder open a new ruby file we can do this through using the built-in serializer generator. Simply jumping into our console and running the following command will do the work for us.

rails g serializer car

Now we can take a look at what the generated file looks like. It should look something like this.

# app/serializers/car_serializer.rb
class CarSerializer < ActiveModel::Serializer
  attributes :id
end
Enter fullscreen mode Exit fullscreen mode

Now if we visit our localhost:3000/cars we will see all the Ids of our cars in other words we can control what json we want to render by simply adding the attributes into our serializer. In our case lets get rid of the :id attribute and just add the year, make, and model of the cars.

# app/serializers/car_serializer.rb
class CarSerializer < ActiveModel::Serializer
  attributes :year, :make, :model
end
Enter fullscreen mode Exit fullscreen mode

Now if we visit localhost:3000/cars we will see the following

[
  {
    "year": 2015,
    "make": "Toyota",
    "model": "Corolla"
  }
]
Enter fullscreen mode Exit fullscreen mode

BOOM! With that, we just greatly reduced the JSON we are sending to the frontend while also maintaining separation of concerns now we can return our controller to it's original state like so.

class CarsController < ApplicationController
  def index
     cars = Car.all
     render json: cars, status: :ok
  end
end
Enter fullscreen mode Exit fullscreen mode

Now this looks super cleaned up! Under the hood whenever we use render json: rails will follow the naming conventions and implicitly look for a serializer that matches the name of the model. This is all thanks to rails being a convention over configuration framework and active model serializer complementing this.

This is amazing and all but let's say we want to take this a step further and customize the JSON data even more. We can do this through custom serializer methods!

Custom Methods

Let's say we want to put the year, make, and model in a string and tell the user the engine size the car has

[
  "car_summary": "2015 Toyota Corolla - Engine Size 1.5 liter
]
Enter fullscreen mode Exit fullscreen mode

To do this we are going to have to create a custom method. To start we are going to have to define and add our custom method to our attributes. While we are at it we are going to drop a byebug in the method as well

 # app/serializers/car_serializer.rb
class CarSerializer < ActiveModel::Serializer
  attributes :car_summary

  def car_summary
    byebug
  end
end
Enter fullscreen mode Exit fullscreen mode

So you may be wondering how am I going to get access to the year, make, model, and engine size within this method? Well if we jump into the byebug and type self the instance that is returned includes an object attribute which also has the first car instance. This means that you can use self.object and whatever attribute you want to access. Let's try making the JSON we want to return with string interpolation.

 # app/serializers/car_serializer.rb
class CarSerializer < ActiveModel::Serializer
  attributes :car_summary

  def car_summary
    "#{self.object.year} #{self.object.make} #{self.object.model} - Engine Size #{self.object.engine_size} liter"
  end
end
Enter fullscreen mode Exit fullscreen mode

Now we will get the following JSON.

[
  "car_summary": "2015 Toyota Corolla - Engine Size 1.5 liter"
]
Enter fullscreen mode Exit fullscreen mode

Conclussion

Managing the JSON an API returns and how it is returned is very important. This causes less stress for our APIs and less work for the frontend which in turn makes everything more responsive. Active Model Serializer gem makes this possible and is very easy to understand.

Top comments (0)