Rails API and Serializers: How to Send Better Data
In rails, a serializer allows you to customize data instead of having a default render.
In this article, we’ll look at a step by step guide to using the serializer in your application.
The problem with the Rails API
Rails is a great way to be used as an API with the render json method. However, the JSON data is often full of things you don’t want and doesn’t offer many options for customization.
Let’s say you want to query a list of dogs and their owners from your database. We’ll define the two models and routes:
rails g model Person
rails g model Dog
Let’s define our routes and controllers
rails g controller Dogs
rails g controller People
Now our PeopleController will look like this:
We seed our database with a list of people and dogs. In your seeds.rb file, you can have:
Then run the command
rails db:seed
This command will help you seed your database with new data. That way, you can make API calls to retrieve them.
Now let’s define our routes :
These routes will help us query all the dogs in the database as well as the people.
Here are the two routes I am creating with the GET method:
GET http://localhost:3000/dogs
GET http://localhost:3000/dogs/:id
We’ll be more interested in querying the dog's endpoint.
Querying data without a serializer
After defining our routes, controllers, and seeding our database, we can use the available routes to query a list of dogs.
To do that, we’ll use Postman. Postman is a software development tool that helps you make API calls and test them. If you haven’t already, I recommend you install it. Not only will it help you in this tutorial, but as well in your daily work.
Download Postman here
With Postman installed, let’s start our Rails server using the default port with the command:
rails server ou simply rails s
Next step, open Postman:
Let’s say you want to query a list of all the dogs available in the database, using the normal routes we previously said. With Postman, we can make a GET request to handle it. Make sure you start your Rails server and copy the routes into Postman (for a GET request)
The default data will give you :
[{"id": 1,"name": "Lisa","breed": "German shepherd","age": 3,"created_at": "2020-08-28T07:55:40.579Z","updated_at": "2020-08-28T07:55:40.579Z","person_id": 1},{"id": 2,"name": "Buddy","breed": "Labrador Retriever","age": 1,"created_at": "2020-08-28T07:55:40.602Z","updated_at": "2020-08-28T07:55:40.602Z","person_id": 1},{"id": 3,"name": "Rocky","breed": "Husky","age": 4,"created_at": "2020-08-28T07:55:40.625Z","updated_at": "2020-08-28T07:55:40.625Z","person_id": 1}]
In this case, we are getting a list of dogs with the name, breed, person_id, etc.
But do you need all this information? Is there anything else you would like to know about each of those dogs? For example, each dog has its owner. But in this data, we only get a “user_id”. Not that intuitive…
As well, I don’t need to know when data was created or updated. This includes some customization when the app renders. And you can do this with a serializer!
Using the serializer gem
The active_model_serializer gem allows you to customize the JSON file you render. Here’s the same JSON file as before, but with a serializer.
{"id": 1,"name": "Lisa","age": 3,"breed": "German shepherd", "person": { "id": 7, "name": "John Doe"}
Do you see the difference? Now, we have an owner and removed the created_at and updated_at keys. Let’s see how we can do it step by step.
First, let’s install our serializer. For that, we use the gem active_model_serializer. So add this line in your gemfile.
gem ‘active_model_serializer’
In your Rails app, run:
bundle install
Creating your first serializer
The next step is to create a serializer for a model you want to query data from. Let’s follow our example and decide to serialize our Dog model.
In your terminal, run:
rails generate serializer Dog
This command creates a new folder called serializers (in your ‘app’ folder) and a new file called dog_serializer.rb like this:
The default attribute is :id . This means when we make a new call to our dog index endpoint, the serializer will take care of the render and return what is in the attributes (hence only id here)
If we make a new request, we get:
[{"id": 1},{"id": 2},{"id": 3}]
That’s it! Now we are taking control of the rendering of our JSON file! We can add as many elements to our attributes and it will show in our rendering.
Let’s say we want to only show the id, name, breed, and age of the dog. We can add all these attributes to our serializer:
[{"id": 1,"name": "Lisa","age": 3,"breed": "German shepherd"},{"id": 2,"name": "Buddy","age": 1,"breed": "Labrador Retriever"},{"id": 3,"name": "Rocky","age": 4,"breed": "Husky"}]
And you can put(or omit) whatever attribute of dog you want to render. This includes as well as pictures or the owner of each dog. Let’s see now how we can render the owner for each dog:
For that, we’ll add the following line to the DogsSerializer class:
belongs_to: :person
This line adds the owner (person) while rendering the data like this:
[{"id": 1,"name": "Lisa","age": 3,"breed": "German shepherd", "person": { "id": 7, "name": "John Doe", "age": 36, "created_at": "2020-08-29T16:54:32.605Z", "updated_at": "2020-08-29T16:54:32.605Z" },
... Rest of data ...]
You can even customize the “person” data by creating a serializer for the Person model:
rails g serializer person
Then in person_serializer.rb :
This returns our customized data with only the name and id of that person:
[{"id": 1,"name": "Lisa","age": 3,"breed": "German shepherd","person": {"id": 7,"name": "John Doe",},
... Rest of data ...]
That’s it! Now you understand how to use a serializer in Ruby on Rails.
Using serializer is a great way to customize the data you render. Not only this, but you can also attach a picture(link) associated with the model and send its link in your JSON file as well. In this case, you’ll need to use Active Storage.