Using “include:” in a Sinatra ApplicationController

Coy Reid
5 min readSep 15, 2021

--

In this blog, I will go over how to use “include” inside Sinatra Application Controller when calling the “.to_json()” method. This blog pertains to projects using Ruby/ActiveRecord/Sinatra as the backend and React as the frontend.

You wondering what I’m even talking about

Before I hop into it, let me define what exactly a Sinatra Application Controller is…

An Application Controller is part of a software pattern known as Model-View-Controller or MVC. The core concept of this software pattern is the separation of concerns of different parts of an application.

Models are responsible for interacting with the database, Views are responsible for controlling what the user sees on the page, and Controllers handle the receiving of requests and using the Model to generate and respond with data needed by the View.

The Application Controller in our Ruby backend handles what endpoints we will fetch to from inside our React frontend. Here is an example of a basic Application Controller file:

This is based on a database set up with a Games table, Users table, and a Reviews table as a join between the two. There is also a Comments table that belongs to both a User and Review

Here we first inherit methods from Sinatra::Base (on line 1) which opens the doors to various options to use inside our Controller file.

Second, we set the default content type for each CRUD action to ‘application/json’, (line 3) which cuts out some of the code you’d have to write.

Lastly, there is a method starting on line 5 that will handle what happens when we fetch to the “/games” endpoint with a GET request. In this example, it would return all the Game instances.

With this setup, the frontend would successfully receive all the games when making a GET request to this endpoint. But with this example’s table relation setup, what if we want to fetch all the games but also be able to see its associated reviews? Well, you’d do something like so:

Note the only change here is adding “include: :reviews” inside the “.to_json()” method. “:reviews” in this example is the name of the associated table tied to the Games table. So since the Reviews table has a foreign key tied directly to a Game id, we are able to fetch not just a Game but its associated reviews as well. The result of this call (shown through Postman) went from this:

To this:

But what if we also wanted to have all the comments for each review and info about the user tied to that review? Well, you’d use another include:

Notice the syntax change. First, include (line 7) now points to a hash, and reviews now acts as a key in that hash, so its colon symbol was flipped to the other side. The value set to this key is another hash with another include inside, this time pointing to an array that has the other associated tables to be included. (If it was just one, you wouldn’t need an array)

New results from postman

But what if you also wanted to know about the user who made that specific comment on this specific review? Well, you’d add ANOTHER include:

Notice again the syntax change… Comments (line 11) is now acting as a key pointing to a hash, which inside has the 3rd “include” this time pointing to user. The colon was again flipped, just like before with reviews.

The result of making a GET request to this endpoint would be an array of Game Objects, now with not just its table-specific columns included but also its associated table relations. So in the frontend, you can see the reviews associated with a specific game, the info about the users who made those reviews, the comments associated with that review, and the info about the users who made those comments.

PHEW, that’s a lot of data in one GET request… And doesn’t this code look a little.. messy? You can clean it up a bit by extracting what’s happening inside the .to_json() method into a separate method inside the ApplicationController class. Like so:

What this method does is take in whatever command is passed in and calls the same .to_json() method onto it. So now all you’d have to do in your GET method is pass in whatever data you are retrieving as an argument to this new “serialize” method. Like so:

Isn’t that so much nicer to look at? Plus it’s reusable, like if you wanted to retrieve just one game at a time, not all the games, but still have all the associated data tied to that game (method on line 9) :

I hope this helps you out in whatever project you may be working on! Having all the associated data from one GET request makes the React side of things much easier.

Have a great day!

--

--