Building Simple Web Apps with Ruby, Part 4

Following on from the other posts in this series, here I want to focus more on the static and dynamic content aspects. This will actually be fairly tame stuff for the most part but it’s a way to make sure we can do some of the basics with Sinatra — just in time to change them all around a bit.

First, let’s clean up the index.erb. We’ll start this process of by creating a file called adhoc.erb in your views directory. This will just be a file where you can test out certain things before they become part of your web application. Now move only the form part from index.erb to the adhoc.erb file. Your adhoc.erb should look like this:

Please note that I changed the action value so the url referenced is now “/adhoc” rather than “/”. With that done, let’s clean up index.erb so that it looks like this:

What you’ll probably notice is that while I’m still using HTML, I took away all the surrounding elements that HTML tends to have, such as the <html> and <body> tags. I’ll come back to why I did that momentarily.

In order for the new adhoc.erb page to be viewed, you will have to add a route to your script. You can probably guess how to do this based on what you already have in place. Here is what you need to do:

Finally, since I changed where the form action goes to, you should change your post route handler so it looks like this:

Now you can visit http://localhost:9292/ and http://localhost:9292/adhoc to see your “minified” pages. At this point all of the surrounding ‘template’ HTML stuff has been removed, including the title tag. But since it’s valid HTML it all still shows up just fine. Still, though, this is not the way to do web development? In the “wild west” days of web development it was fine to leave out just about everything and have the browsers (hopefully) compensate for our lackluster web development skills. (Ah, the bad old days. Miss them? Me either.)

So how do we get all that back? Well it’s probably obvious that we could just include all of the scaffolding HTML in the index.erb and adhoc.erb files. And any other files we create. Or we could use a layout. So here we’ll construct a layout that Sinatra will use for all of your pages.

Provide a Common Layout

In the views directory create a file called layout.erb. Put the following (or something like it) in place:

With that file in place, if you now visit both of your pages you will see that both have the layout you provided in the layout file. This works because Sinatra automatically looks in the views directory for a layout template file to render before loading any other views. The extension looked for depends on what you are using for your template engine. Since I have used ERB, the file sought is layout.erb.

The really important line in that layout.erb file is the Ruby yield method. That will return the contents of whatever page is being called at that point in the layout file. Pretty handy! So basically what happens is this:

  1. Sinatra sees a GET request for the adhoc page using the erb template engine.
  2. Sinatra looks for a layout.erb file in the views directory.
  3. Sinatra looks for an adhoc.erb file in the views directory.
  4. Sinatra generates the content to display from the layout.erb file.
  5. The ERB template engine sees the yield statement embedded in layout.erb.
  6. The yield state tells Sinatra “yield to whatever page was called and display its content here”.
  7. Sinatra generates the content to display from the adhoc.erb file.
  8. Sinatra sends the layout.erb + adhoc.erb content to the browser.

One thing this has done, however, has made every page have the same title. This is because the title tag is specified in the layout. This is another area where we can be a little dynamic. First change the title tag in your layout.erb to the following:

If you want to see how your Sinatra app generates stack traces, browse to one of your pages with that line in place.

To have this work, add the following to your route handlers:

All I did there was create an instance variable that is available to the route. That variable is available to the dynamic resource called up by that route. Since layout is called up for all resources, it too can use the instance variable. Granted, this is about the most common trick in the book for Sinatra apps but it’s a good example of how you can use instance variables to pass information to your application.

Sinatra Can Flash

Now let’s try to add another feature of Sinatra: flash messages. These are used to display a message within a session. The most common use for this is when you have a form that submits, generates a message, and sends you to another page. Well, in this case sending you to another page causes you to not see the message, right? (It’s not a bug! It’s a feature!!) What you really need is for the message to appear on the page that you were directed to so that, you know, you have a chance of actually reading it.

So the first thing we have to do is require the Sinatra flash module. If you followed the first post, you already got the gem for this. So add the following to your script file:

What we’ve done here is establish that our Sinatra application is configured to use sessions. Now, I will add here that I’m doing about the simplest thing possible in terms of setting sessions. Things can get much more involved than this. For now, however, I’m keeping it simple.

Here I’ve also made sure that the Sinatra Flash module is available to us. However, this isn’t quite enough. Remember that Gemfile? You have to make the following addition to that:

Then you have to run the following at the command line:

bundle update

Note that this is necessary any time you have to include a new gem in your project. Also note that this is a case where you will have to restart the server because it needs to be re-executed in the context of the added gem. Just in case it’s not clear: the reason the above is necessary is because it generates a new Gemfile.lock file and that file is what sets up the execution environment, in terms of saying what gems are required to execute your application.

Now let’s use our new module to produce a flash message. Change your post route handler message to look like this:

Also note I’ve added a redirect line there to redirect the form submission to the root page. Keep in mind what’s happening here. A post action is being done on the “/adhoc” page and a message is being generated on that page. What this means is that the message will be lost during the redirect. So what Sinatra is doing here is saving that message as part of the session. In order to display it, we have to modify our layout.erb file as follows:

Wow! Look at all that, huh? This is actually more than you need but what I’ve done here is put in some embedded logic that says if a flash notice has been generated — and we know our route handler does generate one — then display that notice. The same applies to an flash error. The paragraph tags would just allow you to style the errors to look a certain way.

So if you now go to http://localhost:9292/adhoc and submit the form with some text, what should happen is that the root page is displayed and the message appears near the top of the page. Obviously the message isn’t too obvious, which is probably why you would want to style it.

And that brings up a good point: stylesheets. How do we use them in this Sinatra world? And, for that matter, what about JavaScript? Yeah, those are good questions.

Stylesheets and JavaScript

So let’s add some CSS and JavaScript. Now, I don’t want to go crazy here because I want to eventually switch up a few things in terms of how I’ve structured everything. So let’s do something simple to get a JavaScript file in place. Let’s also create a simple stylesheet. If nothing else, we can style that flash message of ours.

Add the following line to the head section of your layout.erb file:

Now the key thing to note here is that Sinatra is going to default to looking in the public directory for this path. You can instruct Sinatra to do things differently but, for right now, I see no reason to. So create a directory called css in the public directory. (If you had previously deleted the public directory, recreated it.) Within that css directory create a file called style.css. Obviously you can style things how you want. Here’s something to get you started just so you can verify that your css file is being read:

If you now go to http://localhost:9292 and submit a message via the form, you should now see that the flash message is green.

So that’s pretty simple. You use style sheets just as you normally would. The key thing is knowing that, by default, Sinatra is going to go looking in the public directory.

Now let’s add some JavaScript and make sure that works. Add the following line to your layout file in the head section:

Once again, Sinatra is going to be looking in your public directory by default. So just create a directory called js in the public directory and, within the js directory, create a file called application.js. You could just put a simple alert() method call in that file and see if it triggers when you visit the page. (It would.) But let’s make sure that a page can actually call and use the JavaScript.

So create a new page called stardate.erb in your views directory. You’re going to have to create a route for this page in your app.rb file. Feel free to try that on your own. (I’ll show you how I did it in a bit but it’s nothing you haven’t already seen.) In this file put the following:

Now in application.js put the following:

Remember to put in that route! Here’s how I did it:

Now if you go to http://localhost:9292/stardate you should see that you can click the Convert button and get a calendar value for whatever five digit stardate you enter.

Note: Since these are five digit stardates, these are strictly new era — “The Next Generation”, “Deep Space Nine”, and “Voyager”. You will not be able to compute old era (“The Original Series”) with this calculator.

As I said at the start, this post is kind of tame in that very little here was anything other than just basic web development. Granted, you now know how to use flash a little bit. It might not hurt for me to explore that a bit more in a future post. But most importantly what you’ve seen here is that you can use JavaScript and CSS in the way you normally would with your HTML. This is all handy because in the next post I want to talk about how you can use a different templating engine for your markup and how you can use one of the streamlined CSS variants. This latter area, incidentally, is an area of great debate among some.


This article was written by Jeff Nyman

Anything I put here is an approximation of the truth. You're getting a particular view of myself ... and it's the view I'm choosing to present to you. If you've never met me before in person, please realize I'm not the same in person as I am in writing. That's because I can only put part of myself down into words. If you have met me before in person then I'd ask you to consider that the view you've formed that way and the view you come to by reading what I say here may, in fact, both be true. I'd advise that you not automatically discard either viewpoint when they conflict or accept either as truth when they agree.

2 thoughts on “Building Simple Web Apps with Ruby, Part 4”

  1. I made a few mistakes typing in the code which proved to be a great learning experience debugging what I’d done wrong.
    Roll on the next post – how many are there going to be ?

    – and once again, many thanks, I’ll blog about this once it’s finished

    1. As far as how many, not sure. I know of at least two more I’d like to get to if for no other reason than that they contain material I wish had been presented to me when I was learning. Beyond those two I can maybe see one more that covers some database related specifics. Particularly because using a database locally and then using Heroku to host that database could prove interesting.

      Glad these are helping you out a bit. I know for me I started getting light bulbs going off when I could actually see how to deploy. I also really like Sinatra. Granted, it’s no Rails — but when you don’t need the full power of Rails, that’s not a bad thing. Although, that being said, I think the next two posts are going to show how you can at least start to align your Sinatra usage with how Rails expects things to be done.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.