Apps with Ruby Sinatra and RESTful Routes, a Simple Breakdown

Eva Yi Zheng
Nerd For Tech
Published in
8 min readMar 1, 2021

I love building! Whether it be Nanoblocks, Metal Earth models, or programs, I just love building. I was recently introduced to the Sinatra library for Ruby, and it is definitely mind-blowing.

For anyone new to coding (such as myself), a library is a set of code that was made by very, very generous coders. Libraries make our lives easier because we won’t have to worry about re-defining and repeating the basic codes that exist in almost every app. Sinatra is a library for building basic websites.

However, just being given a library is definitely a risky move. For one thing, I only know the bare basics of how the Sinatra library works. I have been just following code-alongs so I was quite scared that I don’t know how I would use this knowledge to code my own Sinatra website. What better way to learn about Sinatra from its roots than to write an article about it, right?

Installation

As with any gem (the name for a Ruby library), we have to install it!

In our terminal, we run gem install sinatra.

And in any file that we need to use Sinatra, we simply have to require ‘sinatra’ on top of the file.

RESTful Routes

Can you imagine being a developer for Company X and you would write routes (what a user would see as the URL) like companyx.com/codingproject/title/edit/user3/blah/bluh. And then you have to write another route with possibly a similar function that would look nothing like the first one. Yikes.

Now imagine you’re going to transfer to Company Z because you can’t stand how Company X wants you to write the routes… only to find out that Company Z doesn’t have a nice way of writing routes that would be easy to code. Big Yikes.

In 2000, Roy Fielding changed all of that nonsense with his REST concept. REST stands for REpresentational State Transfer. It all breaks down to just having routes that actually represent what the server is trying to show to the user. It sounds like common sense to us now, but it wasn’t the case when the Internet was still a new phenomenon.

There are 7 RESTful routes and they correspond to the four ways we interact with data, CRUD (Create, Read, Update, Delete).

Create of CRUD

Have you ever signed up for a website? How about a sweepstake? And Instagram?

When we signup on websites, we’re first taken to a page to fill out info about us. Then we submit the information to the website so that we may receive the product or service that site is providing. Any time you’re submitting information on a site, you’re submitting a form to that site! With the information from the form, the site can save you down to their database.

The C of CRUD takes 2 routes to fully function. Let’s use Pokémon throughout our examples! For my project, the star classes were Entry, Organizer, and Task, but they’re not as fun as Pokémon. I love talking about Pokémon, so let’s continue to use Pokémon in the following examples.

Photo by Michael Rivera 🇵🇭 on Unsplash

Let’s imagine we have a Pokémon class that exists in pokemon.rb. This Pokémon class will inherit from ActiveRecord::Base (yet another library that helps us define methods that interact with databases.

The Pokémon class will look something like this.

class Pokemon < ActiveRecord::Base
end

By inheriting from ActiveRecord, our Pokémon class will have access to methods like .create, which automatically saves our instance to the database! But this article will not be concentrating on ActiveRecord.

Anyway, back to the 2 routes of the C of CRUD. They are:

get ‘/pokemon/new’ do
erb :new
end

and

post ‘/pokemon’ do
@pokemon = Pokemon.create(params)
redirect to "/pokemon/#{@pokemon.id}"
end

You can imagine that you can replace Pokémon with any class that you want. That is the magic of REST.

The get method comes from the Sinatra library. Whenever you see get, it’s safe to assume that you’ll just be showing something to the user. erb is also a Sinatra method which takes in a symbol as an input. What you usually want to use as an input is the form that you’ll be showing or a page that will show the form.

params is an instance method given to us by Sinatra that has a return value of a hash. You can think of it as a hash that stores information from the form that was filled out by the user. Forms is another topic of its own and it will be hard to explain everything in one article. But you can imagine the params method will retrieve all the info that the user inputs. From those inputs, we can create our Pokémon instance.

redirect to is similar to erb in that it is a method that shows the response to the user. One big difference is that erb does not change the URL for the user while redirect to will change to the URL to match that of the input.redirect to takes in a get route that you’ve defined.

We use instance variables within the methods because if we were to just use redirect to “/pokemon/#{pokemon.id}”, the “/pokemon/#{pokemon.id}” route technically will have no idea what a Pokémon is because that route is technically a different method, so we want to share the Pokémon info with the separate method.

Read of CRUD

Think of Instagram. You can look at a user’s home page to see all of her pictures or you can go to a specific image and admire its glory on its own separate page. So the R of CRUD will also take 2 routes, one for all the instances of Pokémon and one for just one specific instance of Pokémon. It will be:

get ‘/pokemon’ do
@pokemon = Pokemon.all
erb :index
end

and

get ‘/pokemon/:id’ do
@pokemon = Pokemon.find_by(id: params[:id})
erb: show
end

The first method is setting an instance variable for all the instances of Pokémon and the instance variable will be transferred to the index.erb file. The index.erb file will then list all the instances.

The second method is showing a specific instance of Pokémon. Depending on the layout of the show.erb file, the page might show the specific Pokémon’s type, moves, and picture.

Update of CRUD

To update is to edit. Before the application can make any edits, the application must know what to edit. Thus, first we have to show the user the form that he can use to edit. It will look something like this:

get ‘/pokemon/:id/edit’ do
@pokemon = Pokemon.find_by(id: params[:id])
erb :edit
end

In this route, we are asking for the id value from the URL through the params method. Once the Pokémon is found with the find_by method, we can render the edit.erb file.

Once the user makes his edits, the info will go through the patch route:

patch ‘/pokemon/:id/edit’ do
pokemon = Pokemon.find_by(:id params[:id])
pokemon.update(params)
redirect to '/pokemon/#{pokemon.id}'
end

This route is similar to the previous one in that it will also try to find the Pokémon through the params from the URL. The next line, we will be using ActiveRecord’s update method to meta-update every attribute (just like how it was done in the Create route). Then we will redirect the user to the /pokemon/#{pokemon.id} route. We have to interpolate the pokemon.id part because the input of the redirect to method is a string! We use redirect to because we want to show the user a different URL. If we were to just use the erb method, the URL would stay as /pokemon/:id/edit.

At this point, you might be wondering, “Why do we have to find the Pokémon every time?”

Well, it all seems magical to us when we browse through the Internet and the browser doesn’t seem to be asking for us to login every time we go to a new page. However, the Internet was created to be stateless, meaning every new page is essentially a new page! The application has to make up for that by asking for the Pokémon’s id in every request.

But the TLDR for the magic of a browser’s “memory” is the involvement of sessions and cookies. Cookies is your passport to every site. Every time you go to a site, your passport will get “stamped”. The browser will look at your passport to identify who you are and where you should be going.

Photo by Megan McClain on Unsplash

Delete of CRUD

So CRUD has 7 routes and we have covered 6 so far, meaning the delete route only has one method:

delete ‘/pokemon/:id/delete’ do
pokemon = Pokemon.find_by(id: params[:id])
pokemon.delete
redirect to '/pokemon'
end

By now, this will all seem familiar. We don’t need an instance variable because we are redirecting and also because we are deleting a record! No need to assign a local variable if we are just going to delete it.

After we find the Pokémon with the id value from the params method, we will be using the ActiveRecord delete method to delete the record from our database. Depending on how you want your application to be, you could redirect the user to other paths other than the /pokemon route, but it is simply convention to do so.

Photo by Thimo Pedersen on Unsplash

Conclusion

It’s important to remember that a dynamic web application would be hard to maintain without a proper database and detailed forms.

From working on my own Sinatra project, I learned that it’s very hard to get the perfect schema for my tables in my first try.

The secret to perfecting your forms is to use the pry gem and actually seeing what the return value of params is! There were a lot of trial and errors in using the correct syntax but writing this article alongside coding my project really helped me maintain the RESTful conventions.

In the end, it’s all about separation of concerns. REST is super helpful in separating which folders should contain which files and which files should contain what classes/methods. That being said, don’t forget to use the MVC (models, views, controllers) concept!

--

--