Rails + JavaScript, Endpoints using Active Model Serializers, JSON to the Rescue

 

I have been using Rails for a while now, and I love every bit of it, Rails is considered an end to end framework, what does that mean? well, It means that you can use it to build the server side of your application (back-end) and the client side (front-end) as well.

But we live in times where as much as we want to simplify tasks, as a developer you might be asked to build your back-end using rails because it’s awesome! and the client side might be done using a different framework such as Angular Js, and in order to connect one with the other, you are going to need end points.

End Points

An end point is simply a unique URL that represents an object or a collection of objects, where you simplify client access to data from other applications.

logomakr_9ye1cf

Let’s say you ask facebook to let you use all their users data for some app you are building (good luck with that!), imagine the process of typing that manually, or if they send you an email with a database file in god knows what format, but lets say you manage to parse and use that data, what happens when this data gets updated? as data constantly does, would you like to keep requesting for data update emails on every single data change?… if your answer was “Hell no!!” (as it should be), then you are going to love API end points, they allow you to access real-time data in a serialized format called JSON.

What is JSON?jason3

JSON is short for JavaScript Object Notation, and is a way to store information in an organized, easy-to-access manner. In a nutshell, it gives us a human-readable collection of data
that we can access in a really logical manner.

This is to say, that if you have a ruby User object with some attributes, you can extract that data in JSON format so it can be used by other frameworks, like so:

#Ruby
jason = User.new
jason.name = "Jason"
jason.last_name = "Voorhees"
jason.dob = "June 13, 1946"
jason.status = "Open to a relationship"
jason.favorite_day = "Friday"
jason.favorite_number = 13

#Ruby Object
<User:0x007fd6e30152b8 @name="Jason", @last_name="Voorhees", 
@dob="June 13, 1946", @status="Open to a relationship", 
@favorite_day="Friday", @favorite_number=13>

Turned into JSON:

const jason = { 
  "name" : "Jason", 
  "last_name" : "Voorhees", 
  "dob" : "June 13, 1946", 
  "status" : "Open to a relationship", 
  "favorite_day" : "Friday", 
  "favorite_number" : "13" 
}

Neat right? now the data is formatted to be used by a front-end framework or to respond to AJAX calls, you name it, but how do we get ruby data formatted into beautiful JSON? That’s where Active Model Serializers come in.

Active Model JSON Serializer (AMS)

Provides a basic serialization to a serializable_hash for your objects, it returns a hash representing the model. – Rails API

Meaning, it takes ruby objects and turns them into JSON, but how?

giphy-8

Let’s say we are building a blog app with posts and authors, and a post has a title, and a description, while an author has a name.

class Post < ApplicationRecord
  belongs_to :author
end

class Author < ApplicationRecord
  has_many :posts
end
# Create Author
stephen = Author.new
stephen.name = "Stephen King"
stephen.save # stephen.id = 1
# Create Post
post = Post.new
post.title = "A Blog Post By Stephen King"
post.description = "This is a blog post by Stephen King. It will probably be a movie soon."
post.author = stephen
post.save # post.id = 1

First, we need to add the gem to our Gemfile:

# Gemfile
#...
gem 'active_model_serializers'

Run  bundle install to activate the gem.

Create an app/serializers directory:

mkdir serializers
├── Gemfile
├── Gemfile.lock
├── Rakefile
├── app
│   ├── serializers
│

Now we need to generate an ActiveModel::Serializer for our Post. Thankfully, the gem provides a generator for that. Drop into your console and run:

rails g serializer post

If we look at the generated post_serializer.rb, inside the serializers directory, it should look something like this:

class PostSerializer < ActiveModel::Serializer
  attributes :id
end

We want to get some more information out of it, so let’s add a couple attributes.

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :description
end

To make use of our new serializer, we need to let our controller know that it can use it.

# posts_controller.rb
 def show
    @post = Post.find(params[:id])
    respond_to do |format|
      format.html { render :show }      # Render post in HTML format
      format.json { render json: @post} # Render post in JSON format
    end
  end

But wait? what is that format.json { render json: @post  } madness? well, here we are simply creating an end point, meaning that now you can visit two URL’s, one will render your good old HTML (www.myapp.com/post/1), and another the will render a JSON formatted object (www.myapp.com/post/1.json), calling render json: @post would implicitly use the new ActiveModel::Serializer to render the post to JSON.

Let’s see it in action. Restart your Rails server and browse to /posts/1.json and look at the results. It should look like this:

{
  post: {
    id: 1,
    title: "A Blog Post By Stephen King",
    description: "This is a blog post by Stephen King. It will probably be a movie soon."
  }
}

Worked like a charm!

Pro-Tip: You can use JSONView chrome app to render JSON in your browser window in a much nicer way.

What’s missing ? The author name. So how do we do that?

We need to create a new AuthorSerializer.

rails g serializer author

And add the author name to the list of attributes:

class AuthorSerializer < ActiveModel::Serializer
  attributes :id, :name
end

Now to test this out, let’s modify our authors_controller#show action to handle a JSON request:

class AuthorsController < ApplicationController
  def show
    @author = Author.find(params[:id])
    respond_to do |f|
      f.html { render :show }
      f.json { render json: @author }
    end
  end
end

And load up /authors/1.jsonWe should see something that looks like this:

{
  author: {
    id: 1,
    name: "Stephen King"
  }
}

But how to add the author name to our post JSON?

We add a has_one :author to our PostSerializer:

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :description
  has_one :author
end

Top-tip: You might notice that we’re using has_one in our serializer, when in the model, the post -> author relationship is actually a belongs_to. This can be confusing at first, but AMS is only concerned with the number of the relationship, not the direction. So it only knows has_one and has_many. This is because it’s not describing a data/model relationship, but the relationship as defined by the JSON.

Reload /posts/1.json we will now see our author information.

{
  post: {
    id: 1,
    title: "A Blog Post By Stephen King",
    description: "This is a blog post by Stephen King. It will probably be a movie soon.",
    author: {
      id: 1,
      name: "Stephen King"
    }
  }
}

Now we have all our post information formatted to JSON, meaning our data can be accessed now by your favorite front-end framework.

giphy-7

Yay we did it!

Resources

Flatiron School Online Learn Program

JSON: What It Is, How It Works, & How to Use It

You may also like