Singing with Sinatra

Singing with Sinatra

Tutorial Details
  • Topic: Sinatra / Ruby
  • Difficulty: Beginner
This entry is part 1 of 3 in the Singing with Sinatra Session
Next »

Welcome to Track 1 of “Singing with Sinatra.” In this mini-series we’ll be taking a look at Sinatra; a small, yet incredibly powerful DSL for quickly creating Ruby web applications. In this part, we’ll get started with Sinatra by playing around with a few routes, learning how to access URL parameters and how to POST data between pages.

If you haven’t worked with Ruby before, you should check out the Ruby for Newbies session, where Andrew will guide you through the process of installing Ruby on your system and learning the basics of the language.

First thing we need to do is install the Sinatra RubyGem. Enter the following into the Terminal:

gem install sinatra

Also install the ‘shotgun‘ gem, which we’ll use later:

gem install shotgun

Depending on how you have RubyGems set up on your system, you may need to prefix the gem install commands with sudo.


The Very Basics

Open your text editor and create a new file named basics.rb. Right at the top we need to require RubyGems and the Sinatra gem:

require 'rubygems'
require 'sinatra'

Note: If you’re running Ruby 1.9 (which you should be ;)), you can drop the require 'rubygems' line as Ruby automatically loads RubyGems anyway.

Let’s start off by creating the classic “Hello World”. Add the following to your basics.rb application file:

get '/' do
  "Hello, World!"
end

This is a ‘Route’. Here, we’re telling Sinatra that if the home, or root, URL '/' is requested, using the normal GET HTTP method, to display “Hello, World!”

Now, in the terminal, let’s start up the server by typing ruby basics.rb. We’re told that Sinatra has “taken the stage” on port 4567, and if we go to http://localhost:4567/ in a browser, we see “Hello, World!”.

So let’s try another page:

get '/about' do
  'A little about me.'
end

Whenever you make a change to your Sinatra app you have to restart the server.

This mean if the '/about' URL is requested (using the GET HTTP method), “A little about me.” will display.

Whenever you make a change to your Sinatra app you have to restart the server. So to save us the hassle of constantly stopping & starting the server during development, we’ll use the Shotgun gem we installed earlier.

Stop the current Sinatra server with Ctrl-C. Now we can run shotgun basics.rb and Shotgun will automatically restart the server every time we refresh the page. This is useful when we’re doing a lot of development work, but as the whole application is being restarted, it can be slow.

As Shotgun’s listening on a different port, let’s move to port 9393 and go to http://localhost:9393/about in your browser. You should see the phrase we set.


Accessing URL Parameters

You can also access parameters from the URL. Add the following to your basics.rb file:

get '/hello/:name' do
  params[:name]
end

In this example, we have a route where anything after '/hello/' will be contained in a params array with the key :name. The params array contains all GET and POST variables. If you’re coming from a PHP background, this is similar to the $_REQUEST global array.

In the browser, go to, for example, http://localhost:9393/hello/dan and you should see the name displayed back (“dan”).

You could incorporate the :name into a string by wrapping it in ${...}. Try replacing the params[:name] line with:

"Hello there, #{params[:name]}."

As you’d expect, we can use all the normal Ruby methods on the variable, such as .upcase, .reverse etc.

"Hello there #{params[:name].upcase}."

You can set the route to accept multiple query string variables like so:

get '/hello/:name/:city' do
  "Hey there #{params[:name]} from #{params[:city]}."
end

As well as normal variables in a URL, Sinatra allows you to include retrieve wildcard query strings, known as a ‘splat’, by using an asterisk like so:

get '/more/*' do
  params[:splat]
end

Anything included in the URL after /more/ will be accessible through the :splat key in the params array.


View Files & POST

Now let’s do something a little more interesting. Let’s create a form to retrieve data from the user, then do something with it. We’ll also make use of a “view file”, which allows us to split the markup for a view into a separate file. Add the following route to your basics.rb app file:

get '/form' do
  erb :form
end

This route will load the form.erb ERB (Embedded Ruby) file from a views/ directory. ERB files are typically normal HTML files which allow you to include Ruby code inside <% … %> tags, which will be parsed before being sent to the browser – just like how you include PHP or ASP code in a webpage.

So create a views/ directory in the same folder as the basics.rb file. And inside views/, create the file named form.erb with the following content inside:

hello from the view

Point your browser at http://localhost:9393/form and you should see the message we set in the view file.

Now we know that everything’s working, change the contents of that file to:

<form action="/form" method="post">
  <input type="text" name="message">
  <input type="submit">
</form>

Refresh the page and you should see the form:

But, enter a message into the text box and click the submit button, and you’ll see Sinatra’s error page informing us that a route doesn’t exist for this URL.

You may be wondering why this is, seeing as the form is submitting to /form, the same URL the form is on, so there shouldn’t be a problem. Well, the difference is that we’re retrieving this page through the POST HTTP method – and as you can see on the error page Sinatra presents us, Sinatra requires a different route for each HTTP method.

So add the following route to the Sinatra app:

post '/form' do
  "You said '#{params[:message]}'"
end

This route is for the POST method, not GET. Also, all POST variables are available in the same params array as GET variables, so we can retrieve the message submitted with the form. Try it out!


You Could Totally Work For MI5 Now!

So what next? Let’s create a way to ‘encrypt’ a message we send so that it can only be read by our intended recipient. Add the following route to the Sinatra app:

get '/secret' do
  erb :secret
end

You’re probably getting the hang of this by now. This route will load the ERB view file at views/secret.erb. Create that view file with the following:

<h3>Super Secret MI5 Message Encryptor!</h3>
<form action="/secret" method="post">
  <input type="text" name="secret">
  <input type="submit">
</form>

And create the route for the POST method:

post '/secret' do
  params[:secret].reverse
end

OK, so now we’ve got a message encryptor which uses a special ‘reverse’ method to make the message seemingly unreadable, we need a way to decrypt the message:

get '/decrypt/:secret' do
  params[:secret].reverse
end

There you have it! A super secret, highly secure message encryptor good enough for any country’s intelligence agency.

Legal Disclaimer: When we say “highly secure” and “encryption”, we’re actually just reversing the letters. Sorry.


FourOhFour?

One final thing we’ll touch on is 404 error pages. Right now if you go to a URL which there isn’t a route for (eg. /danisthebest), you’ll see Sinatra’s fancy error message. On a real app we’d want to display our own error. To do this, simply use the not_found route, like so:

not_found do
  status 404
  'not found'
end

Here we’re using Sinatra’s status method to set the HTTP status code of the page to 404 (you could use this same method to set any status code, such as 201 when something is created, or 403 when a login was unsuccessful).

You could further refactor the not_found route by using Sinatra’s halt method:

not_found do
  halt 404, 'page not found'
end

Conclusion

So you’ve performed your first duet with Sinatra! Hopefully you can see how easy this DSL makes creating web apps.

On the next track, we’ll be creating a simple “to-do” app hooked up to a SQLite database. We’ll also take a look at the elusive PUT and DELETE HTTP methods no-one’s heard of.

Note: You can browse the final project files for this tutorial over at GitHub.

Dan Harper is danharper on Themeforest
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://twitter.com/nvartolomei Nicolae Vartolomei

    Pretty cool tutorial for Ruby beginners.

  • istoselidas

    Very nice sinatra tutorial. Waiting for the next more advanced tutorial with sqlite! Thank you

  • Arthur Corenzan

    Ruby is just magical! *-*

    Started with Sinatra 2 weeks ago, it blew my mind away!

    Nice tutorial, cheers!

  • http://partialbits.com Partialbits

    Nice tutorial , and I followed every thing , but when I tried xss , I was surprised to that it was actually showing the text in h1 tags.is there any standard way to block all xss attacks ?

    Regards

    • http://www.danharper.me Dan Harper
      Author

      Add the following to your Sinatra application file (basics.rb):

      helpers do
      include Rack::Utils
      alias_method :h, :escape_html
      end

      Now you can use a ‘h’ function to escape HTML in views. For example:

      (alternatively written as , but the above method is the “Ruby Way”).

      This will be mentioned properly in part 3.

      • http://www.danharper.me Dan Harper
        Author

        WordPress butchered that comment. Basically:

        (alternatively written as , but the above method is the “Ruby Way”).

        Remove the space between the ).

      • http://www.danharper.me Dan Harper
        Author

        Bloody hell. I’ll try that again (just noticed we can use pre tags in comments):

        <%=h params[:message] %>

        (alternatively written as <%= h(params[:message]) %>, but the above method is the “Ruby Way”).

  • medokin

    I wanted to start with ruby, so i tried Ruby on Rails. I gave it up.

    But this tut has motivated me again. Thanks a lot!

    • http://www.danharper.me Dan Harper
      Author

      Sinatra is probably a much better place to start off at than Rails. :)

      • medokin

        Therefore, I am looking forward to the next tutorial.

  • medokin

    Im on Win7 and Ruby works fine. Even when i run “ruby basics.rb” the server works, but if i try to run “shotgun basics.rb”, i get an error. Google has nothing to say about it.

    c:/Ruby192/lib/ruby/gems/1.9.1/gems/shotgun-0.9/bin/shotgun:142:in `trap’: unsupported signal SIGQUIT (ArgumentError)
    from c:/Ruby192/lib/ruby/gems/1.9.1/gems/shotgun-0.9/bin/shotgun:142:in `block in ‘
    from c:/Ruby192/lib/ruby/gems/1.9.1/gems/shotgun-0.9/bin/shotgun:141:in `each’
    from c:/Ruby192/lib/ruby/gems/1.9.1/gems/shotgun-0.9/bin/shotgun:141:in `’
    from c:/Ruby192/bin/shotgun:19:in `load’
    from c:/Ruby192/bin/shotgun:19:in `’

    • medokin

      Shotgun doesnt work well on win32.

      I found a simular gem “sinatra-reloader”, works on win32.

      https://github.com/rkh/sinatra-reloader

      • http://www.danharper.me Dan Harper
        Author

        Yeah, the Shotgun gem is Linux/Mac only as it uses some system libraries.

      • medokin

        You should mention that in your posts. This was very confusing. ;)

  • http://blog.leehsueh.com hl

    the not_found route doesn’t seem to work for me (running ruby/sinatra on windows xp). regardless of if i have the route defined or not, i get a generic browser “this link is broken.” anyone know why this might be?

    • http://danharper.me Dan Harper
      Author

      That’s odd. I can’t seem to find any other references to this problem. It may be due to Windows. Are you sure you’ve defined the route correctly?

    • http://www.github.com/dotink/inkwell Matthew J. Sahagian

      If I’m not mistaken some browsers show a default 404 page of their own if the returned information is below a certain size — lame, but I’m fairly sure that’s the case.

      • Dennis Carlsson

        For chrome ex. A file must be at least 500 characters to display an “special” 404 page

      • http://www.danharper.me Dan Harper
        Author

        Ah, yes, this is probably it. As Dennis said, Chrome will display its own error page if the page is under 500 chars long. (I had forgot about this as I run the Dev channel for Chrome where I assume it’s disabled as it works fine for me).

  • http://www.warpconduit.net Josh Hartman

    This is the least confisuing ruby code i’ve ever seen. Keep it coming!

  • Torrance

    I’m feeling stupid here, but what is a ‘DSL’? Searching the interwebs didn’t help clarify anything for me.

    And what sort of role does Sinatra fill? Does it replace the webserver/fastcgi(or mod_language) duo with an app that handles both aspects? If so, what does this mean for performance? Does it also handle serving of static files too or are these handed off to a seperate server?

  • http://www.dailygrind.it Sergio

    Sinatra is great…. if only it had some more support by hosters….

  • rsludge

    Very good tutorial, I like Sinatra, because it’s very fast and simple.
    I wish next parts will be even more interesting

  • http://studiomagnolia.com Cesare

    Hi,

    nice start. If you plan a series on Sinatra please consider describing the deployment task.

    • http://www.danharper.me Dan Harper
      Author

      Good idea. I’ll go over Heroku deployment in part 3.

  • http://www.rebatesense.com RebateSense

    Can’t agree more…eagerly waiting for the SQLite episode and some deployment walk-throughs. RoR deployment overhead was a big turn off for me to not venture into it.

  • http://www.emersonlackey.com Emerson

    Been meaning to give Sinantra a try. The simplicity of the code is so refreshing. I’ve been using CakePHP a fair bit, but it seems a little too heavy for my tastes.

    • moosc

      You can try padrino:

      Padrino is a ruby framework built upon the excellent Sinatra Microframework. Sinatra is a DSL for quickly creating simple web applications in Ruby. Padrino was created to make it fun and easy to code more advanced web applications while still adhering to the spirit that makes Sinatra great!

      http://www.padrinorb.com/

      • http://www.danharper.me Dan Harper
        Author

        I’ll have to take a look at this! Looks great.

  • http://www.helloeverything.co.uk David

    Wow, great little tutorial, i’ve just started learning Ruby on Rails after 4/5 years working with PHP.

  • http://www.twemotion.org Twemotion

    Hey Dan, great tutorial. Just a quick question, so is Sinatra an alternative to Rails, or do they have different scopes?

  • http://www.danharper.me Dan Harper
    Author

    Sinatra is typically used for smaller projects than Rails.

  • Juan

    Nice intro Dan, thank you.

  • http://topikutama.com Ali

    nice tutorial …..
    god bless you…

  • http://carlosvidal.pe Carlos Vidal

    hey Net Tuts, you should write a Session tutorial like this one for Fat-Free PHP Framework. It is the same ideas as Sinatra.

  • AlanB

    Keen to try Sinatra but I’m using Windows XP and getting error:

    “C:/Ruby19/lib/ruby/gems/1.9.1/gems/rack-1.3.5/lib/rack/backports/uri/common_192.rb:53:in `remove_const’: constant URI::WFKV_ not defined (NameError)”

    There is a reference to the problem at: https://github.com/rack/rack/pull/247
    where Shanev removed the fix but how do I do that??

    Regards

  • http://kevinmil.es Kevin Miles

    Possible Typo:
    Under View Files and POST you use the URL
    http://localhost:9393/form

    Did you mean http://localhost:4567/form
    ?

  • Jake

    Fantastic tutorial! It seems shotgun doesn’t work with Windows 7 given a fork(2) dependency (see here: http://stackoverflow.com/questions/1814903/running-fork2-from-windows-with-cygwin-possible) and was wondering if anyone knows a workaround.

    Cheers,
    Jake

    • istivan

      From medokin above:

      “Shotgun doesnt work well on win32.
      I found a simular gem sinatra-reloader, works on win32.”

      Now, the reloader is now part of sinatra-contrib.

      Usage instructions are found here, on sinatra’s webiste and installations instructions here.

      However, calling gem install sinatra-contrib I got a bunch of errors :S

    • istivan

      In addition to my previous comment, I looked at the dependencies for sinatra-contrib and went about installing them (and their dependencies too) one by one. Eventually I found the culprit: eventmachine. And, after much searching, I came across this on Quora and installed this version of eventmachine, which worked, and sinatra-contrib installed too. phew!

      • Matias

        Phew! I struggled with the same problem, and luckily installing eventmachine did the magic. Thanks, I owe you a dime!

  • http://iphonetipsandtricks.lookitupforme.com John Varghese

    That was a good start to learning Sinatra. Thanks.

  • baiki

    Re: FourOhFour?

    Mutated vowels not working. How to change to UTF-8?

    main.rb:14: invalid multibyte char (US-ASCII)
    main.rb:14: syntax error, unexpected $end, expecting keyword_end
    halt 404, “page nöd found”

    Cheers,
    Baiki

  • http://spencercooley.me Spencer

    Reallly great tutorial. I hooked the /form post method into twilio to send text messages! Yah!

  • Luis Viera

    Thanks for this contribution! :)

  • Reddy

    good tutorial everything working except shotgun command. please illustrate about shotgun.

  • JK

    Loved it.

  • emas

    thanks

  • juco

    Great introduction!