Lesson Weekend

In this lesson, we'll cover the basics of routing with Sinatra. Sinatra is a minimalist Ruby framework for building server-side web applications. It is neither as popular nor as high-powered as Rails. However, Sinatra is a great tool for learning about routing because we'll manually create all our routes in a file named app.rb. Rails will mostly handle routing for us, which means Rails isn't as helpful for understanding this essential concept.

Create a folder called sinatra_routing_example and add the following two files to the root directory: a Gemfile and a file called app.rb.

The Gemfile should look like this:

sinatra_routing_example/Gemfile
source('https://rubygems.org')

gem('sinatra')
gem('rspec')
gem('pry')

Make sure to bundle after you've created the Gemfile.

Now add the following code to app.rb:

sinatra_routing_example/app.rb
require('sinatra')

get('/') do
  "This will be our home page. '/' is always the root route in a Sinatra application."
end

get('/albums') do
  "This route will show a list of all albums."
end

get('/albums/new') do
  "This will take us to a page with a form for adding a new album."
end

get('/albums/:id') do
  "This route will show a specific album based on its ID. The value of ID here is #{params[:id]}."
end

post('/albums') do
  "This route will add an album to our list of albums. We can't access this by typing in the URL. In a future lesson, we will use a form that specifies a POST action to reach this route."
end

get('/albums/:id/edit') do
  "This will take us to a page with a form for updating an album with an ID of #{params[:id]}."
end

patch('/albums/:id') do
  "This route will update an album. We can't reach it with a URL. In a future lesson, we will use a form that specifies a PATCH action to reach this route."
end

delete('/albums/:id') do
  "This route will delete an album. We can't reach it with a URL. In a future lesson, we will use a delete button that specifies a DELETE action to reach this route."
end

get('/custom_route') do
  "We can even create custom routes, but we should only do this when needed."
end

First, we require Sinatra so we can use its functionality. Sinatra provides methods like get, post, patch and delete.

Note that each route gets its own do...end block. Each block provides a set of instructions for our application that will be executed when the route is reached. Normally, we'd put code in here, but for now, we'll just have each block render a string.

Let's check it out. Go to the terminal, cd to the root directory of the project, and enter ruby app.rb. The terminal will return the following output (output may vary slightly):

== Sinatra (v2.2.1) has taken the stage on 4567 for development with backup from Puma
Puma starting in single mode...
* Puma version: 5.6.4 (ruby 3.1.2-p20) ("Birdie's Version")
*  Min threads: 0
*  Max threads: 5
*  Environment: development
*          PID: 10452
* Listening on http://[::1]:4567
* Listening on http://127.0.0.1:4567
Use Ctrl-C to stop

The terminal gives us some useful information:

  • We need to go to localhost:4567 to see our application. Local host just means the computer the application is running on. The number after the colon is the port number. Users on other computers do not have access to this application. We will always navigate to localhost:4567 to interact with our application (unless we set another port number).
  • We are in a development environment. For the rest of the course, we will be working with frameworks and libraries that use development environments. This is in contrast to a test environment (used for testing) and a production environment, used for deployment.
  • We can exit our application by typing in Ctrl-C.

A few notes:

  • Puma is a web server. If you don't see output from Puma, but instead WEBrick, know that this is simply another server. Puma is considered more efficient, so if you want to switch to Puma, it's as simple as running gem install puma in the command line. Next time you start your Sinatra app, it will automatically use Puma. Puma is the default server for Rails, so you'll use it either way when we start working with Rails.
  • Windows users may notice warnings like *** SIGUSR2 not implemented, signal based restart unavailable!. This means that your Windows system can't recognize certain signals that are meant for UNIX-based systems; these signals are used for ending ("killing") processes in a specific way. However, this should not cause issues in the normal functioning of our Sinatra apps, so you should ignore these warnings. If you want to explore resolving these warnings, you can try using a different web server or using Windows Subsystem for Linux (WSL).

Now open the browser and navigate to localhost:4567. This is where our application lives when Sinatra running.

  • We will see the following: "This will be our home page. '/' is always the root route in a Sinatra application." Our Sinatra applications should always include a root path. Otherwise, users will see an error page instead of a home page. For instance, in the case of our record store, bestundergroundrecords.com would lead to an error page and users would have to navigate to bestundergroundrecords.com/albums instead. Unfortunately, they'd probably just end up assuming that the website doesn't work at all.

  • Try typing in the following URLs: localhost:4567/albums and localhost:4567/albums/new. We will be routed to the corresponding blocks of code.

  • Next, try typing in the following URL: localhost:4567/albums/72. Our application will return the following string: "This route will show a specific album based on its ID. The value of ID here is 72."

Each block has access to a params hash. Dynamic values in a URL, link or form will be passed to the params hash. For the route above, we'll eventually call a find method to retrieve the album and we'll need an ID to do that. More on this later.

  • Note that we can't just type in a URL and access routes that utilize POST, PATCH or DELETE. After all, we wouldn't want users to update or delete albums just by navigating to a page. Any time we type in a URL or click on a simple link, it is a GET request. In future lessons, we'll cover how to use forms and buttons to reach POST, PATCH and DELETE routes.

  • Try navigating to localhost:4567/custom_route. Sinatra doesn't care what we name our routes — remember, our naming conventions are in place to make life easier for other coders and users. RESTful naming conventions should be used for all CRUD-related functionality.

  • Now try typing in a URL that doesn't match any of the routes listed above. For instance, we could type in localhost:4567/nothing_here. Sinatra will return an error message:

Sinatra shows a message that reads "Sinatra doesn't know this ditty."

This is a very common error. If a route doesn't exist, Sinatra will return the error message "Sinatra doesn't know this ditty." This error will only occur if the route does not exist in app.rb. There are generally two possible solutions to this error:

  • There is a typo in the URL. Check to make the URL is correctly spelled and try again.

  • The route does not exist in app.rb and needs to be added.

We've successfully created routes for our application's CRUD functionality. However, our application is only rendering strings. Over the next several lessons, we'll build out our application to include back-end logic and views. However, that will all use plain old Ruby code. All Sinatra-related code we'll cover in the next few weeks is contained in app.rb.

Terminology


Local host: The machine an application is running on.

Port number: The part after the colon in localhost:4567. We can configure our port number but generally it makes sense to use the default port.

Root path: Denoted by a / in app.rb. This is the home page.

params hash: Sinatra passes information from a URL or form to a route in app.rb via this hash.

  • Development environment: An environment for developing code.

  • Test environment: An environment for running tests.

  • Production environment: A live environment where code is deployed for real-world users.

Using Sinatra


  • To run Sinatra, go to root directory of project and type:
ruby app.rb
  • To exit Sinatra, type Ctrl-C.

  • To look at a running application in the browser, navigate to localhost:4567.

  • If a route doesn't exist, Sinatra will return the error message "Sinatra doesn't know this ditty."

Routing Example


require('sinatra')

get ('/') do
  "This will be our home page. '/' is always the root route in a Sinatra application."
end

get ('/albums') do
  "This route will show a list of all albums."
end

get ('/albums/new') do
  "This will take us to a page with a form for adding a new album."
end

get ('/albums/:id') do
  "This route will show a specific album based on its ID. The value of ID here is #{params[:id]}."
end

post ('/albums') do
  "This route will add an album to our list of albums. We can't access this by typing in the URL. In a future lesson, we will use a form that specifies a POST action to reach this route."
end

get ('/albums/:id/edit') do
  "This will take us to a page with a form for updating an album with an ID of #{params[:id]}."
end

patch ('/albums/:id') do
  "This route will update an album. We can't reach it with a URL. In a future lesson, we will use a form that specifies a PATCH action to reach this route."
end

delete ('/albums/:id') do
  "This route will delete an album. We can't reach it with a URL. In a future lesson, we will use a delete button that specifies a DELETE action to reach this route."
end

get ('/custom_route') do
  "We can even create custom routes, but we should only do this when needed."
end

Lesson 6 of 37
Last updated August 7, 2022