How to Serialize Your Rails Backend

Using ActiveModel::Serializer

Marisa Canan-Zucker
The Startup
5 min readOct 31, 2019

--

What is serialization?

The main idea: the process of organizing, or re-organizing, data to suit your needs

Why?

  • It will make your life easier when building the frontend
  • It keeps your code DRY! (Don’t Repeat Yourself) Instead of writing the same code 5 different times in each Controller action, write it once in your Serializer
  • Reduces the number of fetch requests needed
  • Allows you to nest resources more easily

How?

One of my favorite aspects of programming is that there are infinite ways to accomplish any goal. With that in mind, I’m going to walk through how I used ActiveModel::Serializer to organize data for my Rails backend.

Before we get started, take a few moments to think about these four models and their relationships.

1. Create your app from the terminal.

rails new my-app-backend --api --database=postgresql

I am using a Postgres database so I can later deploy my application on Heroku. While Postgres is not required here, --api is. This tells Rails that your ApplicationController should inherit from ActionController::API instead of the usual ActionController::Base. It also lets Rails know you don’t need to create Views, just Models and Controllers.

Note: when using Postgres, you will have to open the Postgres app, ensure a server is running, then run rails db:create in your terminal before you can run any migrations. Once the Postgres server is running, it will display any tables previously created. As long as you leave the Postgres server running in the background, you can now minimize its window. No further actions will be required.

LEFT: server is not running, RIGHT: server is running

2. Add ActiveModel::Serializer to your Gemfile and run bundle install in your terminal.

gem 'active_model_serializers', '~> 0.10.0'

3. Create models, controllers, routes, and serializers all at once by running rails g resource in your terminal:

rails g resource User email first_name last_name avatar

This will create the following files:

app/models/user.rb

app/controllers/users_controller.rb

app/serializers/user_serializer.rb

db/migrate/<timestamp>_create_users.rb

as well asresources :users in config/routes.rb

Create resources for the rest of your models:

rails g resource Project title subtitle user_id:integerrails g resource Prompt content img prompt_type project_id:integerrails g resource Answer prompt_id:integer content correct:boolean

After checking that your schemas are correct, run rails:db:migrate and add relationships to your models

4. Seed your database with some fake data! I created 1 user with 2 projects. Each project had 10 prompts. Each prompt had 4 answers (1 correct, 3 incorrect).

5. Set up Controllers. To ensure I could play around with my data structure from any route, I wrote index and show actions for all of my models. I won’t actually need both for every model, but I can go back and delete them later. In the planning stages, it’s better to have something and not need it, than to need it and not have it.

Start up your server!

Here is a screenshot of each index page currently:

This is great, and definitely better than the structure we get without serializers, which would include all of our timestamp columns.

However, this will still require us to make 4 seperate fetches just to get all the data related to a single project.

6. Decide how you want your data to be structured. This is the most difficult part of the process. Think about when you will make your fetches from your front end. What models should be grouped together to reduce the number of fetches needed?

To start I added relationships to my Serializers. ActiveModel::Serializer supports has_many and belongs_to relationships.

Like magic, we can now see all of our related data nested in each index!

7. Make it your own! For this specific app, I want my data to fit a very specific structure. Let’s go through our User model.

I want to be able to see a user’s projects, but currently it is showing me the user_id within each project, even though it’s nested within a user object. Adding relationships to the Serializers results in Rails calling on the ProjectSerializer from within the UserSerializer. To avoid this default behavior, I’m going to comment out my relationships for now and write custom attributes. Just like any Ruby class, we can write instance methods! I’m going to write one called projects. I can then add :projects as an attribute of my UserSerializer.

When I go to a User show page now, I should see a key of projects with an array of that user’s projects. Each Project should only have keys for its’ id, title, and subtitle.

These instance methods can be written to show anything, not just related models.

For example, let’s add something random to our UserSerializer.

So, make your API your own! Happy Coding!

If you would like to see how I chose to serialize the rest of my data, check out the screenshots below.

--

--