Skip to Content
Course content

34: Building a Basic Sinatra Web App

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Wait, how do I actually start a Sinatra app without a massive configuration file?

That's the beauty of Sinatra. Unlike Rails, which gives you a whole city's worth of folders and files before you've even written a line of logic, Sinatra is "minimalist." I usually start with a single file. Let's say we're building a simple "Reading List" app to track books I want to get to.

First, you'll need the gem: gem install sinatra. Then, you just create a file—let's call it app.rb—and define your routes. A route is basically telling Sinatra: "When the user visits this URL using this HTTP method, run this block of code."

require 'sinatra'

get '/books' do
  "Here is a list of all my favorite books!"
end

get '/about' do
  "This app was built to keep my library organized."
end

If you run ruby app.rb, Sinatra starts a web server on port 4567. I remember the first time I did this; it felt like magic that a few lines of Ruby could suddenly be accessed via a browser.

How do I make pages that change based on what the user types in the URL?

You don't want to hardcode a route for every single book in your database. That would be a nightmare. Instead, we use "named parameters." In Sinatra, you put a colon before a word in the path to tell the app, "Whatever is in this spot is a variable."

These variables get stuffed into a special hash called params. Here is how I'd handle a request for a specific book:

# Let's pretend we have a data store
BOOKS = {
  "1" => "The Hobbit",
  "2" => "Neuromancer",
  "3" => "Foundation"
}

get '/books/:id' do
  book_id = params[:id]
  book_name = BOOKS[book_id]
  
  if book_name
    "You are looking at: #{book_name}"
  else
    status 404
    "Book not found!"
  end
end

Now, if you visit /books/2, Sinatra assigns "2" to params[:id], and you get "Neuromancer" back. It's a simple pattern, but it's the backbone of almost every dynamic site you've ever used.

Is there a better way to handle HTML than just returning long strings?

Absolutely. Returning strings from a route is fine for a quick test, but it becomes an absolute mess once you start adding CSS or complex layouts. For that, we use ERB (Embedded Ruby). It lets you write standard HTML and sprinkle Ruby code inside it where you need dynamic data.

To make this work, you create a folder named views in the same directory as your app.rb. Inside that folder, you create .erb files. In your route, you use the erb method to render that file.

One key thing: if you want a variable to be available inside your ERB template, you must make it an instance variable (starting with @) in your Ruby code. Local variables disappear as soon as the route block ends.

# In app.rb
get '/books' do
  @book_list = ["The Hobbit", "Neuromancer", "Foundation"]
  erb :index
end

Then, in views/index.erb, you can loop through that list:

<h1>My Reading List</h1>
<ul>
  <% @book_list.each do |book| %><li><%= book %></li><% end %></ul>

Notice the difference between <% %> (which executes code but doesn't print anything) and <%= %> (which prints the result directly into the HTML). I've spent more time than I'd like to admit debugging a page only to realize I forgot the equals sign.




📋 Practical Task

Exercise: Building a Dynamic Book Detail Page

Your goal is to expand the Reading List app so that it doesn't just list books, but provides a dedicated detail page for each one using a template.

  • Create a hash called BOOK_DETAILS where the keys are IDs (e.g., "1", "2") and the values are short descriptions of the books.
  • Create a route /book/:id that retrieves the description from the hash based on the URL parameter.
  • Assign the description to an instance variable (e.g., @description).
  • Create a view file called details.erb that displays the description inside an <p> tag.
  • Ensure that if a user enters an ID that doesn't exist in your hash, the page displays a friendly "Book not found" message instead of crashing.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.