14 min read

(For more resources related to this topic, see here.)

Step 1 – creating the application

The first thing to do is set up Sinatra itself, which means creating a Gemfile.

  1. Open up a Terminal window and navigate to the directory where you’re going to keep your Sinatra applications.
  2. Create a directory called address-book using the following command:

    mkdir address-book

  3. Move into the new directory:

    cd address-book

  4. Create a file called Gemfile:

    source 'https://rubygems.org'gem 'sinatra'

  5. Install the gems via bundler:

    bundle install

    You will notice that Bundler will not just install the sinatra gem but also its dependencies. The most important dependency is Rack (http://rack.github.com/), which is a common handler layer for web servers. Rack will be receiving requests for web pages, digesting them, and then handing them off to your Sinatra application.

    If you set up your Bundler configuration as indicated in the previous section, you will now have the following files:

    • .bundle: This is a directory containing the local configuration for Bundler
    • Gemfile: As created previously
    • Gemfile.lock: This is a list of the actual versions of gems that are installed
    • vendor/bundle: This directory contains the gems

    You’ll need to understand the Gemfile.lock file. It helps you know exactly which versions of your application’s dependencies (gems) will get installed. When you run bundle install, if Bundler finds a file called Gemfile.lock, it will install exactly those gems and versions that are listed there. This means that when you deploy your application on the Internet, you can be sure of which versions are being used and that they are the same as the ones on your development machine. This fact makes debugging a lot more reliable. Without Gemfile.lock, you might spend hours trying to reproduce behavior that you’re seeing on your deployed app, only to discover that it was caused by a glitch in a gem version that you haven’t got on your machine.

    So now we can actually create the files that make up the first version of our application.

  6. Create address-book.rb:

    require 'sinatra/base'class AddressBook < Sinatra::Base get '/' do 'Hello World!' endend

    This is the skeleton of the first part of our application.

    Line 1 loads Sinatra, line 3 creates our application, and line 4 says we handle requests to ‘/’—the root path. So if our application is running on myapp.example.com, this means that this method will handle requests to http://myapp.example.com/.

    Line 5 returns the string Hello World!. Remember that a Ruby block or a method without explicit use of the return keyword will return the result of its last line of code.

  7. Create config.ru:

    $: << File.dirname(__FILE__)require 'address-book'run AddressBook.new

    This file gets loaded by rackup, which is part of the Rack gem. Rackup is a tool that runs rack-based applications. It reads the configuration from config.ru and runs our application.

    Line 1 adds the current directory to the list of paths where Ruby looks for files to load, line 2 loads the file we just created previously, and line 4 runs the application.

    Let’s see if it works.

  8. In a Terminal, run the following command:

    bundle exec rackup -p 3000

    Here rackup reads config.ru, loads our application, and runs it.

    We use the bundle exec command to ensure that only our application’s gems (the ones in vendor/bundle) get used. Bundler prepares the environment so that the application only loads the gems that were installed via our Gemfile.

    The -p 3000 command means we want to run a web server on port 3000 while we’re developing.

  9. Open up a browser and go to http://0.0.0.0:3000; you should see something that looks like the following screenshot:

Illustration 1: The Hello World! output from the application

Logging

Have a look at the output in the Terminal window where you started the application.

I got the following (line numbers are added for reference):

1 [2013-03-03 12:30:02] INFO WEBrick 1.3.12 [2013-03-03 12:30:02]
INFO ruby 1.9.3 (2013-01-15) [x86_64-linux]
3 [2013-03-03 12:30:02]
INFO WEBrick::HTTPServer#start: pid=28551 port=3000
4 127.0.0.1 - -
[03/Mar/2013 12:30:06]
"GET / HTTP/1.1" 200 12 0.0142
5 127.0.0.1 - - [03/Mar/2013 12:30:06]
"GET /favicon.ico HTTP/1.1" 404 445 0.0018

Like it or not, you’ll be seeing a lot of logs such as this while doing web development, so it’s a good idea to get used to noticing the information they contain.

Line 1 says that we are running the WEBrick web server. This is a minimal server included with Ruby—it’s slow and not very powerful so it shouldn’t be used for production applications, but it will do for now for application development.

Line 2 indicates that we are running the application on Version 1.9.3 of Ruby. Make sure you don’t develop with older versions, especially the 1.8 series, as they’re being phased out and are missing features that we will be using in this book.

Line 3 tells us that the server started and that it is awaiting requests on port 3000, as we instructed.

Line 4 is the request itself: GET /. The number 200 means the request succeeded—it is an HTTP status code that means Success .

Line 5 is a second request created by our web browser. It’s asking if the site has a favicon, an icon representing the site. We don’t have one, so Sinatra responded with 404 (not found).

When you want to stop the web server, hit Ctrl + C in the Terminal window where you launched it.

Step 2 – putting the application under version control with Git

When developing software, it is very important to manage the source code with a version control system such as Git or Mercurial. Version control systems allow you to look at the development of your project; they allow you to work on the project in parallel with others and also to try out code development ideas (branches) without messing up the stable application.

  1. Create a Git repository in this directory:

    git init

  2. Now add the files to the repository:

    git add Gemfile Gemfile.lock address-book.rb config.ru

  3. Then commit them:

    git commit -m "Hello World"

  4. I assume you created a GitHub account earlier. Let’s push the code up to www.github.com for safe keeping. Go to https://github.com/new.
  5. Create a repo called sinatra-address-book.
  6. Set up your local repo to send code to your GitHub account:

    git remote add origin [email protected]:YOUR_ACCOUNT/sinatra-address-book.git

  7. Push the code:

    git push

You may need to sort out authentication if this is your first time pushing code. So if you get an error such as the following, you’ll need to set up authentication on GitHub:

Permission denied (publickey)

Go to https://github.com/settings/ssh and add the public key that you generated in the previous section.

Now you can refresh your browser, and GitHub will show you your code as follows:

Note that the code in my GitHub repository is marked with tags. If you want to follow the changes by looking at the repository, clone my repo from //github.com/joeyates/sinatra-address-book.git into a different directory and then “check out” the correct tag (indicated by a footnote) at each stage.

To see the code at this stage, type in the following command:

git checkout 01_hello_world

If you type in the following command, Git will tell you that you have “untracked files”, for example, .bundle:

git status

To get rid of the warning, create a file called .gitignore inside the project and add the following content:

/.bundle//vendor/bundle/

Git will no longer complain about those directories. Remember to add .gitignore to the Git repository and commit it.

Let’s add a README file as the page is requesting, using the following steps:

  1. Create the README.md file and insert the following text:

    sinatra-address-book ==================== An example program of various Sinatra functionality.

  2. Add the new file to the repo:

    git add README.md

  3. Commit the changes:

    git commit -m "Add a README explaining the application"

  4. Send the update to GitHub:

    git push

Now that we have a README file, GitHub will stop complaining.

What’s more is other people may see our application and decide to build on it. The README file will give them some information about what the application does.

Step 3 – deploying the application

We’ve used GitHub to host our project, but now we’re going to publish it online as a working site. In the introduction, I asked you to create a Heroku account. We’re now going to use that to deploy our code.

Heroku uses Git to receive code, so we’ll be setting up our repository to push code to Heroku as well.

Now let’s create a Heroku app:

heroku createCreating limitless-basin-9090... done,
stack is cedar
http://limitless-basin-9090.herokuapp.com/ |
[email protected]:limitless-basin-9090.git

Git remote heroku added

My Heroku app is called limitless-basin-9090. This name was randomly generated by Heroku when I created the app. When you generate an app, you will get a different, randomly generated name.

My app will be available on the Web at the http://limitless-basin-9090.herokuapp.com/ address. If you deploy your app, it will be available on an address based on the name that Heroku has generated for it.

Note that, on the last line, Git has been configured too.

To see what has happened, use the following command:

git remote show heroku* remote heroku
Fetch URL: [email protected]:limitless-basin-9090.git
Push URL: [email protected]:limitless-basin-9090.git HEAD branch: (unknown)

Now let’s deploy the application to the Internet:

git push heroku master

Now the application is online for all to see:

The initial version of the application, running on Heroku

Step 4 – page layout with Slim

The page looks a bit sad. Let’s set up a standard page structure and use a templating language to lay out our pages.

A templating language allows us to create the HTML for our web pages in a clearer and more concise way.

There are many HTML templating systems available to the Sinatra developer: erb , haml , and slim are three popular choices. We’ll be using Slim (http://slim-lang.com/).

Let’s add the gem:

  1. Update our Gemfile:

    gem 'slim'

  2. Install the gem:

    bundle

We will be keeping our page templates as .slim files. Sinatra looks for these in the views directory.

Let’s create the directory, our new home page, and the standard layout for all the pages in the application.

  1. Create the views directory:

    mkdir views

  2. Create views/home.slim:

    p address book – a Sinatra application

    When run via Sinatra, this will create the following HTML markup:

    <p>address book – a Sinatra application</p>

  3. Create views/layout.slim:

    doctype html html head title Sinatra Address Book body == yield

    Note how Slim uses indenting to indicate the structure of the web page.

    The most important line here is as follows:

    == yield

    This is the point in the layout where our home page’s HTML markup will get inserted. The yield instruction is where our Sinatra handler gets called. The result it returns (that is, the web page) is inserted here by Slim.

    Finally, we need to alter address-book.rb.

    Add the following line at the top of the file:

    require 'slim'

    Replace the get ‘/’ handler with the following:

    get '/' do slim :home end

  4. Start the local web server as we did before:

    bundle exec rackup -p 3000

    The following is the new home page:

    Using the Slim Templating Engine

    Have a look at the source for the page. Note how the results of home.slim are inserted into layout.slim.

    Let’s get that deployed.

  5. Add the new code to Git and then add the two new files:

    git add views/*.slim

    Also add the changes made to the other files:

    git add address-book.rb Gemfile Gemfile.lock

    Commit the changes with a comment:

    git commit -m "Generate HTML using Slim"

  6. Deploy to Heroku:

    git push heroku master

  7. Check online that everything’s as expected.

Step 5 – styling

To give a slightly nicer look to our pages, we can use Bootstrap (http://twitter.github.io/bootstrap/); it’s a CSS framework made by Twitter.

Let’s modify views/layout.slim. After the line that says title Sinatra Address Book, add the following code:

link href
="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-combined.min.css"
rel="stylesheet"

There are a few things to note about this line.

Firstly, we will be using a file hosted on a Content Distribution Network (CDN ). Clearly, we need to check that the file we’re including is actually what we think it is.

The advantage of a CDN is that we don’t need to keep a copy of the file ourselves, but if our users visit other sites using the same CDN, they’ll only need to download the file once.

Note also the use of // at the beginning of the link address; this is called a “protocol agnostic URL”. This way of referencing the document will allow us later on to switch our application to run securely under HTTPS, without having to readjust all our links to the content.

Now let’s change views/home.slim to the following:

div class="container" h1 address book h2 a Sinatra application

We’re not using Bootstrap to anywhere near its full potential here. Later on we can improve the look of the app using Bootstrap as a starting point.

Remember to commit your changes and to deploy to Heroku.

Step 6 – development setup

As things stand, during local development we have to manually restart our local web server every time we want to see a change. Now we are going to set things up with the following steps so the application reloads after each change:

  1. Add the following block to the Gemfile:

    group :development do gem 'unicorn' gem 'guard' gem 'listen' gem 'rb-inotify', :require => false gem 'rb-fsevent', :require => false gem 'guard-unicorn' end

    The group around these gems means they will only be installed and used in development mode and not when we deploy our application to the Web.

    Unicorn is a web server—it’s better than WEBrick —that is used in real production environments. WEBrick’s slowness can even become noticeable during development, while Unicorn is very fast. rb-inotify and rb-fsevent are the Linux and Mac OS X components that keep a check on your hard disk. If any of your application’s files change, guard restarts the whole application, updating the changes.

    Finally, update your gems:

    bundle

  2. Now add Guardfile:

    guard :unicorn, :daemonize => true do `git ls-files`.
    each_line { |s| s.chomp!; watch s }
    end

  3. Add a configuration file for unicorn:

    mkdir config

  4. In config/unicorn.rb, add the following:

    listen 3000

  5. Run the web server:

    guard

Now if you make any changes, the web server will restart and you will get a notification via a desktop message. To see this, type in the following command:

touch address-book.rb

You should get a desktop notification saying that guard has restarted the application.

Note that to shut guard down, you need to press Ctrl + D .

Also, remember to add the new files to Git.

Step 7 – testing the application

We want our application to be robust. Whenever we make changes and deploy, we want to be sure that it’s going to keep working. What’s more, if something does not work properly, we want to be able to fix bugs so we know that they won’t come back.

This is where testing comes in. Tests check that our application works properly and also act as detailed documentation for it; they tell us what the application is intended for. Our tests will actually be called “specs”, a term that is supposed to indicate that you write tests as specifications for what your code should do.

We will be using a library called RSpec . Let’s get it installed.

  1. Add the gem to the Gemfile:

    group :test do gem 'rack-test' gem 'rspec'end

  2. Update the gems so RSpec gets installed:

    bundle

  3. Create a directory for our specs:

    mkdir spec

  4. Create the spec/spec_helper.rb file:

    $: << File.expand_path('../..', __FILE__)
    require 'address-book'
    require 'rack/test'def app
    AddressBook.newendRSpec.configure do |config|
    config.include Rack::Test::Methodsend

  5. Create a directory for the integration specs:

    mkdir spec/integration

  6. Create a spec/integration/home_spec.rb file for testing the home page:

    require 'spec_helper'describe "Sinatra App" do
    it "should respond to GET" do get '/'
    expect(last_response).to be_ok
    expect(last_response.body).to match(/address book/) endend

    What we do here is call the application, asking for its home page.

    We check that the application answers with an HTTP status code of 200 (be_ok).

    Then we check for some expected content in the resulting page, that is, the address book page.

  7. Run the spec:

    bundle exec rspec Finished in 0.0295 seconds1 example, 0 failures

Ok, so our spec is executed without any errors.

There you have it. We’ve created a micro application, written tests for it, and deployed it to the Internet.

Summary

This article discussed how to perform the core tasks of Sinatra: handling a GET request and rendering a web page.

Resources for Article :


Further resources on this subject:


 

LEAVE A REPLY

Please enter your comment!
Please enter your name here