Ruby on Rails Tutorial
Learn Rails by Example
Michael Hartl
Contents
- Chapter 1 From zero to deploy
- Chapter 2 A demo app
- Chapter 3 Mostly static pages
- Chapter 4 Rails-flavored Ruby
- Chapter 5 Filling in the layout
- Chapter 6 Modeling users
- Chapter 7 Sign up
- Chapter 8 Sign in, sign out
- Chapter 9 Updating, showing, and deleting users
- Chapter 10 User microposts
- Chapter 11 Following users
Foreword
My former company (CD Baby) was one of the first to loudly switch to Ruby on Rails, and then even more loudly switch back to PHP (Google me to read about the drama). This book by Michael Hartl came so highly recommended that I had to try it, and the Ruby on Rails Tutorial is what I used to switch back to Rails again.
Though I’ve worked my way through many Rails books, this is the one that finally made me “get” it. Everything is done very much “the Rails way”—a way that felt very unnatural to me before, but now after doing this book finally feels natural. This is also the only Rails book that does test-driven development the entire time, an approach highly recommended by the experts but which has never been so clearly demonstrated before. Finally, by including Git, GitHub, and Heroku in the demo examples, the author really gives you a feel for what it’s like to do a real-world project. The tutorial’s code examples are not in isolation.
The linear narrative is such a great format. Personally, I powered through the Rails Tutorial in three long days, doing all the examples and challenges at the end of each chapter. Do it from start to finish, without jumping around, and you’ll get the ultimate benefit.
Enjoy!
Derek Sivers (sivers.org)
Formerly: Founder, CD Baby
Currently: Founder, Thoughts Ltd.
Acknowledgments
The Ruby on Rails Tutorial owes a lot to my previous Rails book, RailsSpace, and hence to my coauthor Aurelius Prochazka. I’d like to thank Aure both for the work he did on that book and for his support of this one. I’d also like to thank Debra Williams Cauley, my editor on both RailsSpace and the Ruby on Rails Tutorial; as long as she keeps taking me to baseball games, I’ll keep writing books for her.
I’d like to acknowledge a long list of Rubyists who have taught and inspired me over the years: David Heinemeier Hansson, Yehuda Katz, Carl Lerche, Jeremy Kemper, Xavier Noria, Ryan Bates, Geoffrey Grosenbach, Peter Cooper, Matt Aimonetti, Gregg Pollack, Wayne E. Seguin, Amy Hoy, Dave Chelimsky, Pat Maddox, Tom Preston-Werner, Chris Wanstrath, Chad Fowler, Josh Susser, Obie Fernandez, Ian McFarland, Steven Bristol, Wolfram Arnold, Alex Chaffee, Giles Bowkett, Evan Dorn, Long Nguyen, James Lindenbaum, Adam Wiggins, Tikhon Bernstam, Ron Evans, Wyatt Greene, Miles Forrest, the good people at Pivotal Labs, the Heroku gang, the thoughtbot guys, and the GitHub crew. Finally, many, many readers—far too many to list—have contributed a huge number of bug reports and suggestions during the writing of this book, and I gratefully acknowledge their help in making it as good as it can be.
About the author
Michael Hartl is the author of the Ruby on Rails Tutorial, the leading introduction to web development with Ruby on Rails. His prior experience includes writing and developing RailsSpace, an extremely obsolete Rails tutorial book, and developing Insoshi, a once-popular and now-obsolete social networking platform in Ruby on Rails. In 2011, Michael received a Ruby Hero Award for his contributions to the Ruby community. He is a graduate of Harvard College, has a Ph.D. in Physics from Caltech, and is an alumnus of the Y Combinator entrepreneur program.
Copyright and license
Ruby on Rails Tutorial: Learn Rails by Example. Copyright © 2012 by Michael Hartl. All source code in the Ruby on Rails Tutorial is available jointly under the MIT License and the Beerware License.
Copyright (c) 2012 Michael Hartl Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/* * ------------------------------------------------------------ * "THE BEERWARE LICENSE" (Revision 42): * Michael Hartl wrote this code. As long as you retain this * notice, you can do whatever you want with this stuff. If we * meet someday, and you think this stuff is worth it, you can * buy me a beer in return. * ------------------------------------------------------------ */
Chapter 5 Filling in the layout
In the process of taking a brief tour of Ruby in Chapter 4, we added some basic cascading style sheets to our site layout (Section 4.1.2). In this chapter, we’ll add some custom styles of our own, as we fill in the layout with links to the pages (such as Home and About) that we’ve created so far (Section 5.1). Along the way, we’ll learn about partials, Rails routes, and the asset pipeline, including an introduction to Sass (Section 5.2). We’ll also refactor the tests from Chapter 3 using the latest RSpec techniques. We’ll end by taking a first important step toward letting users sign up to our site.
5.1 Adding some structure
The Rails Tutorial is a book on web development, not web design, but it would be depressing to work on an application that looks like complete crap, so in this section we’ll add some structure to the layout and give it some minimal styling with CSS. We’ll also give our code some styling, so to speak, using partials to tidy up the layout once it gets a little cluttered.
When building web applications, it is often useful to get a high-level overview of the user interface as early as possible. Throughout the rest of this book, I will thus often include mockups (in a web context often called wireframes), which are rough sketches of what the eventual application will look like.1 In this chapter, we will principally be developing the static pages introduced in Section 3.1, including a site logo, a navigation header, and a site footer. A mockup for the most important of these pages, the Home page, appears in Figure 5.1. You can see the final result in Figure 5.8. You’ll note that it differs in some details—for example, the footer has four links instead of three—but that’s fine, since a mockup need not be exact.

As usual, if you’re using Git for version control, now would be a good time to make a new branch:
$ git checkout -b filling-in-layout
You might still have the example_user.rb file from Chapter 4 in your project directory; if so, you should probably remove it:
$ rm example_user.rb
5.1.1 Site navigation
When we last saw the site layout file application.html.erb in Listing 4.3, we had just added Blueprint stylesheets using the Rails stylesheet_link_tag helper. It’s time to add a couple more stylesheets, one specifically for Internet Explorer browsers and one for our (soon-to-be-added) custom CSS. We’ll also add some additional divisions (divs), some ids and classes, and the start of our site navigation. The full file is in Listing 5.1; explanations for the various pieces follow immediately thereafter. If you’d rather not delay gratification, you can see the results in Figure 5.2. (Note: it’s not (yet) very gratifying.)
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<%= stylesheet_link_tag 'blueprint/screen', media: 'screen' %>
<%= stylesheet_link_tag 'blueprint/print', media: 'print' %>
<!--[if lt IE 8]><%= stylesheet_link_tag 'blueprint/ie' %><![endif]-->
<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container">
<header>
<%= image_tag("logo.png", alt: "Sample App", class: "round") %>
<nav class="round">
<ul>
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</header>
<section class="round">
<%= yield %>
</section>
</div>
</body>
</html>
One thing to note immediately is the switch from Ruby 1.8–style hashes to the new Ruby 1.9 style (Section 4.3.3). That is,
image_tag("logo.png", :alt => "Sample App", :class => "round")
has been replaced with
image_tag("logo.png", alt: "Sample App", class: "round")
Quite a few prominent Rails developers have started using the new syntax (including RailsCasts host Ryan Bates), and I expect this trend to continue, so it seems wise to start using it now. (The old syntax is deeply entrenched, though, and unfortunately that means most new projects will have a mix of the two, including ours.)
Let’s look at the other new elements in Listing 5.1 from top to bottom. As noted briefly in Section 3.1, Rails 3 uses HTML5 by default (as indicated by the doctype <!DOCTYPE html>); since the HTML5 standard is relatively new, some browsers (especially older versions Internet Explorer) don’t fully support it, so we include some JavaScript code (known as an “HTML5 shiv”) to work around the issue:
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
The somewhat odd syntax
<!--[if lt IE 9]>
includes the enclosed line only if the version of Microsoft Internet Explorer (IE) is less than 9 (if lt IE 9). The weird [if lt IE 9] syntax is not part of Rails; it’s actually a conditional comment supported by Internet Explorer browsers for just this sort of situation. It’s a good thing, too, because it means we can include the extra stylesheet only for IE browsers less than version 9, leaving other browsers such as Firefox, Chrome, and Safari unaffected.
After the lines to include the Blueprint stylesheets (first introduced in Listing 4.4), there is another Internet Explorer–specific line, which this time is a stylesheet that only gets included if the browser is a version of Internet Explorer less than 8 (if lt IE 8):
<!--[if lt IE 8]><%= stylesheet_link_tag 'blueprint/ie' %><![endif]-->
IE has a large number of idiosyncrasies (especially before version 8), and Blueprint comes with a special ie.css file that fixes a bunch of them.
The next section places a container div around our site navigation and content, which is a div tag with class container. This container div is needed by Blueprint (see the Blueprint tutorial for more information). Then there are header and section elements; the header contains the sample app logo (to be added below) and the site navigation (nav). Finally, there is section element containing the site’s main content:
<div class="container">
<header>
<%= image_tag("logo.png", alt: "Sample App", class: "round") %>
<nav class="round">
<ul>
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</header>
<section class="round">
<%= yield %>
</section>
</div>
The div tag in HTML is a generic division; it doesn’t do anything apart from divide the document into distinct parts. In older style HTML, div tags are used for nearly all site divisions, but HTML5 adds the header, nav, and section elements for divisions common to many applications. All HTML elements, including divs and the new HTML5 elements, can be assigned classes2 and ids; these are merely labels, and are useful for styling with CSS (Section 5.1.2). The main difference between classes and ids is that classes can be used multiple times on a page, but ids can be used only once.
Inside the header is a Rails helper called image_tag:
<%= image_tag("logo.png", alt: "Sample App", class: "round") %>
Note that, as with stylesheet_link_tag (Section 4.3.4), we pass a hash of options, in this case setting the alt and class attributes of the image tag using symbols :alt and :class. To make this clearer, let’s look at the HTML this tag produces:3
<img alt="Sample App" class="round" src="/images/logo.png" />
The alt attribute is what will be displayed if there is no image,4 and the class will be used for styling in Section 5.1.2. (Rails helpers often take options hashes in this way, giving us the flexibility to add arbitrary HTML options without ever leaving Rails.) You can see the result in Figure 5.2; we’ll add the logo image at the end of this section.
The second element inside the layout header is a list of navigation links, made using the unordered list tag ul, together with the list item tag li:
<nav class="round">
<ul>
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
This list uses the Rails helper link_to to create links (which we created directly with the anchor tag a in Section 3.3.2); the first argument is the link text, while the second is the URI. We’ll fill in the URIs with named routes in Section 5.3.3, but for now we use the stub URI ’#’ commonly used in web design. Once Rails has processed this layout and evaluated the Embedded Ruby, the list looks like this:
<nav class="round">
<ul>
<li><a href="#">Home</a></li>
<li><a href="#">Help</a></li>
<li><a href="#">Sign in</a></li>
</ul>
</nav>
Our layout is now complete, and we can look at the results by visiting the Home page. In anticipation of adding users to our site in Chapter 7, let’s add a signup link to the home.html.erb view (Listing 5.2).
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
<%= link_to "Sign up now!", '#', class: "signup_button round" %>
As with the previous uses of link_to, this just creates a stub link of the form
<a href="#" class="signup_button round">Sign up now!</a>
Note again the recurring theme of options hashes, in this case used to add a couple CSS classes to the anchor tag. You might notice that the a tag here has two classes, separated by a space:
<a href="#" class="signup_button round">
This is convenient for the common case of an element with two different kinds of styles.
Now we’re finally ready to see the fruits of our labors (Figure 5.2).5 Pretty underwhelming, you say? Perhaps so. Happily, though, we’ve done a good job of giving our HTML elements sensible classes and ids, which puts us in a great position to add style to the site with CSS.

Before we move on to CSS styling, let’s replace the logo alt text with a logo image; you can download the sample application logo at
http://railstutorial.org/images/sample_app/logo.png
Put the logo in app/assets/images so that Rails can find it. (Section 5.2.1 explains the significance of this location.) The result appears in Figure 5.3.

5.1.2 Custom CSS
In Section 5.1.1, you may have noticed that the HTML elements are semantic, that is, they have meaning in English beyond the structure of the page. For example, instead of writing that the navigation menu was “right-top” we used the element “nav”. This gives us considerable flexibility in constructing a layout based on CSS.
Let’s get started by filling in the layout.css file (which you should create at this point) with Listing 5.3. (There are quite a few rules in Listing 5.3. To get a sense of what a CSS rule does, it’s often helpful to comment it out using CSS comments, i.e., by putting it inside /* … */, and seeing what changes.)
app/assets/stylesheets/layout.css
.container {
width: 710px;
}
body {
background: #cff;
}
header {
padding-top: 20px;
}
header img {
padding: 1em;
background: white;
}
section {
margin-top: 1em;
font-size: 120%;
padding: 20px;
background: white;
}
section h1 {
font-size: 200%;
}
/* Links */
a {
color: #09c;
text-decoration: none;
}
a:hover {
color: #069;
text-decoration: underline;
}
a:visited {
color: #069;
}
You can see the results of this CSS in Figure 5.4. There’s a lot of CSS here, but it has a consistent form. Each rule refers either to a class, an id, an HTML tag, or some combination thereof, followed by a list of styling commands. For example,
body {
background: #cff;
}
changes the background color of the body tag to baby blue,6 while
header img {
padding: 1em;
background: white;
}
puts a padding layer of one em (roughly the width of the letter M) around the image (img) inside a header tag. This rule also makes the background color white. Similarly,
.container {
width: 710px;
}
styles an element with class container, in this case giving it a width of 710 pixels (corresponding to 18 Blueprint columns).7 The dot . in .container indicates that the rule styles a class called “container”. (As we’ll see in Section 7.3.2, the pound sign # identifies a rule to style a CSS id in the same way that a dot indicates a CSS class.)

Changing colors is nice, but the navigation links are still hanging down on the left side of the page. Let’s move them to a better location and give them a nicer appearance with the navigation rules in Listing 5.4. The results appear in Figure 5.5. (In some of the book’s code samples, including Listing 5.4, I use three vertical dots to indicate omitted code. When typing in the code, take care not to include the dots; alternatively, if you copy-and-paste the code, make sure to remove the dots by hand.)
app/assets/stylesheets/layout.css
.
.
.
/* Navigation */
nav {
float: right;
background-color: white;
padding: 0 0.7em;
white-space: nowrap;
}
nav ul {
margin: 0;
padding: 0;
}
nav ul li {
list-style-type: none;
display: inline-block;
padding: 0.2em 0;
}
nav ul li a {
padding: 0 5px;
font-weight: bold;
}
nav ul li a:visited {
color: #09c;
}
nav ul li a:hover {
text-decoration: underline;
}
Here nav ul styles a ul tag inside a nav tag, nav ul li styles an li tag inside a ul tag inside a nav tag, and so on.

As the penultimate step, we’ll make the link to our site’s signup page a little more obvious. (Though for the sample app we don’t care, on any real site it’s naturally quite important to make the signup link very prominent.) Listing 5.5 shows CSS to make the signup link big, green, and clickable (so a click anywhere inside the box will follow the link).
app/assets/stylesheets/layout.css
.
.
.
/* Sign up button */
a.signup_button {
margin-left: auto;
margin-right: auto;
display: block;
text-align: center;
width: 190px;
color: white;
background: #006400;
font-size: 150%;
font-weight: bold;
padding: 20px;
}
There are a bunch of rules here; as usual, comment a line out and reload the page if you want to see what each one does. The end result is a signup link that’s hard to miss (Figure 5.6).

As a final touch, we’ll make use of the round class we’ve placed on many of our site elements. Although the current sharp-cornered boxes aren’t terrible, it’s a little friendlier to soften the corners so they won’t slice up our users. We can accomplish this using the CSS code in Listing 5.6, with the results shown in Figure 5.7.
app/assets/stylesheets/layout.css
.
.
.
/* Round corners */
.round {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
It’s worth noting that this trick works on Firefox, Safari, Opera, and Internet Explorer 9, but it doesn’t work on earlier versions of IE. There are ways of getting round corners that work on all browsers, but there’s no other technique that’s even close to this easy, so we’ll just risk leaving some of our IE users with a few tiny cuts.

5.1.3 Partials
Although the layout in Listing 5.1 serves its purpose, it’s getting a little cluttered: there are several lines of CSS includes and even more lines of header for what are logically only two ideas. We can tuck these sections away using a convenient Rails facility called partials. Let’s first take a look at what the layout looks like after the partials are defined (Listing 5.7).
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= render 'layouts/stylesheets' %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container">
<%= render 'layouts/header' %>
<section class="round">
<%= yield %>
</section>
</div>
</body>
</html>
In Listing 5.7, we’ve replaced the stylesheet lines with a single call to a Rails helper called render:
<%= render 'layouts/stylesheets' %>
The effect of this line is to look for a file called app/views/layouts/_stylesheets.html.erb, evaluate its contents, and insert the results into the view.8 (Recall that <%= ... %> is the Embedded Ruby syntax needed to evaluate a Ruby expression and then insert the results into the template.) Note the leading underscore on the filename _stylesheets.html.erb; this underscore is the universal convention for naming partials, and among other things makes it possible to identify all the partials in a directory at a glance.
Of course, to get the partial to work, we have to fill it with some content; in the case of the stylesheet partial, this is just the four lines of stylesheet includes from Listing 5.1; the result appears in Listing 5.8. (Technically, the HTML5 shiv includes JavaScript, not CSS. On the other hand, its purpose is to allow Internet Explorer to understand CSS with HTML5, so logically it still belongs in the stylesheet partial.)
app/views/layouts/_stylesheets.html.erb
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<%= stylesheet_link_tag 'blueprint/screen', media: 'screen' %>
<%= stylesheet_link_tag 'blueprint/print', media: 'print' %>
<!--[if lt IE 8]><%= stylesheet_link_tag 'blueprint/ie' %><![endif]-->
<%= stylesheet_link_tag "application", media: "all" %>
Similarly, we can move the header material into the partial shown in Listing 5.9 and insert it into the layout with another call to render:
<%= render 'layouts/header' %>
app/views/layouts/_header.html.erb
<header>
<%= image_tag("logo.png", alt: "Sample App", class: "round") %>
<nav class="round">
<ul>
<li><%= link_to "Home", '#' %></li>
<li><%= link_to "Help", '#' %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</header>
Now that we know how to make partials, let’s add a site footer to go along with the header. By now you can probably guess that we’ll call it _footer.html.erb and put it in the layouts directory (Listing 5.10).
app/views/layouts/_footer.html.erb
<footer>
<nav class="round">
<ul>
<li><%= link_to "About", '#' %></li>
<li><%= link_to "Contact", '#' %></li>
<li><a href="http://news.railstutorial.org/">News</a></li>
<li><a href="http://railstutorial.org/">Rails Tutorial</a></li>
</ul>
</nav>
</footer>
As with the header, in the footer we’ve used link_to for the internal links to the About and Contact pages and stubbed out the URIs with ’#’ for now. (As with header, the footer tag is new in HTML5.)
We can render the footer partial in the layout by following the same pattern as the stylesheets and header partials (Listing 5.11).
app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= render 'layouts/stylesheets' %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>
</head>
<body>
<div class="container">
<%= render 'layouts/header' %>
<section class="round">
<%= yield %>
</section>
<%= render 'layouts/footer' %>
</div>
</body>
</html>
Of course, the footer will be ugly without some styling (Listing 5.12). The results appear in Figure 5.8.
app/assets/stylesheets/layout.css
.
.
.
footer {
text-align: center;
margin-top: 10px;
width: 710px;
margin-left: auto;
margin-right: auto;
}
footer nav {
float: none;
}
Note here the rule
footer nav {
float: none;
}
that overrides the previous rule
nav {
float: right;
}
so that the footer is centered in the bottom of the page rather than pushed off to the right like the navigation in the header. This convention of having a succession of rules, with subsequent rules possibly overriding previous ones, is what puts the cascading in cascading style sheets.

5.2 Sass and the asset pipeline
One of the most notable differences between Rails 3.0 and more recent versions is the asset pipeline, which significantly improves the production and management of static assets such as CSS, JavaScript, and images. This section gives a high-level overview of the asset pipeline and then shows how to use a remarkable tool for making CSS called Sass, now included by default as part of the asset pipeline.
5.2.1 The asset pipeline
The asset pipeline involves lots of changes under Rails’ hood, but from the perspective of a typical Rails developer there are three principal features to understand: asset directories, manifest files, and preprocessor engines.9 Let’s consider each in turn.
Asset directories
In versions of Rails before 3.0 (including 3.0 itself), static assets lived in the public/ directory, as follows:
public/stylesheetspublic/javascriptspublic/images
Files in these directories are (even post-3.0) automatically served up via requests to http://example.com/stylesheets, etc.
Starting in Rails 3.1, there are three canonical directories for static assets, each with its own purpose:
app/assets: assets specific to the present applicationlib/assets: assets for libraries written by your dev teamvendor/assets: assets from third-party vendors
As you might guess, each of these directories has a subdirectory for each asset class, e.g.,
$ ls app/assets/
images javascripts stylesheets
At this point, we’re in a position to understand the motivation behind the location of the Blueprint CSS files in Section 4.1.2 and the layout.css file in Section 5.1.2. BlueprintCSS is an external CSS framework, so it goes in vendor/assets/stylesheets, whereas layout.css is specific to the sample application, so it goes in app/assets/stylesheets.
Manifest files
Once you’ve placed your assets in their logical locations, you can use manifest files to tell Rails (via the Sprockets gem) how to combine them to form single files. (This applies to CSS and JavaScript but not to images.) As an example, let’s take a look at the default manifest file for app stylesheets (Listing 5.13).
app/assets/stylesheets/application.css
/*
* This is a manifest file that'll automatically include all the stylesheets
* available in this directory and any sub-directories. You're free to add
* application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style
* scope.
*= require_self
*= require_tree .
*/
The key lines here are actually CSS comments, but they are used by Sprockets to include the proper files:
/*
.
.
.
*= require_self
*= require_tree .
*/
Here
*= require_tree .
ensures that all CSS files in the app/assets/stylesheets directory (including the tree subdirectories) are included into the application CSS. The line
*= require_self
ensures that CSS in application.css is also included.
Rails comes with sensible default manifest files, and in the Rails Tutorial we won’t need to make any changes, but the Rails Guides entry on the asset pipeline has more detail if you need it.
Preprocessor engines
After you’ve assembled your assets, Rails prepares them for the site template by running them through several preprocessing engines and using the manifest files to combine them for delivery to the browser. We tell Rails which processor to use using filename extensions; the three most common cases are .scss for Sass, .coffee for CoffeeScript, and .erb for embedded Ruby (ERb). We first covered ERb in Section 3.3.3, and cover Sass in Section 5.2.2. We won’t be needing CoffeeScript in this tutorial, but it’s an elegant little language that compiles to JavaScript. (The RailsCast on CoffeeScript basics is a good place to start.)
The preprocessor engines can be chained, so that
foobar.js.coffee
gets run through the CoffeeScript processor, and
foobar.js.erb.coffee
gets run through both CoffeeScript and ERb (with the code running from right to left, i.e., CoffeeScript first).
Efficiency in production
One of the best things about the asset pipeline is that it automatically results in assets that are optimized to be efficient in a production application. Traditional methods for organizing CSS and JavaScript involve splitting functionality into separate files and using nice formatting (with lots of indentation). While convenient for the programmer, this is inefficient in production; including multiple full-sized files can significantly slow page-load times (one of the most important factors affecting the quality of the user experience). With the asset pipeline, in production all the application stylesheets get rolled into one CSS file (application.css), all the application JavaScript code gets rolled into one JavaScript (javascripts.js), and all such files (including those in lib/assets and vendor/assets) are minified to remove the unnecessary whitespace that bloats file size. As a result, we get the best of both worlds: multiple nicely formatted files for programmer convenience, with single optimized files in production.
5.2.2 Syntactically awesome stylesheets
Sass is a language for writing stylesheets that improves on CSS in many ways. In this section, we cover two of the most important improvements, nesting and variables.
Sass supports a format called SCSS (indicated with a .scss filename extension), which is a strict superset of CSS itself; that is, SCSS only adds features to CSS, rather than defining an entirely new syntax.10 This means that every valid CSS file is also a valid SCSS file, which is convenient for projects with existing CSS files: we can immediately use our existing stylesheets and then convert them to use Sass at our leisure. Since the Rails asset pipeline automatically uses Sass to process SCSS files, we can change the layout.css file to use the filename extension for SCSS:
$ mv app/assets/stylesheets/layout.css app/assets/stylesheets/layout.css.scss
This way the layout file will automatically be run through the Sass preprocessor before being packaged up for delivery to the browser.
Nesting
A common pattern in stylesheets is having rules that apply to nested elements. For example, in Listing 5.3 we have rules both for header and for header img:
header {
padding-top: 20px;
}
header img {
padding: 1em;
background: white;
}
We can replace this in Sass with
header {
padding-top: 20px;
img {
padding: 1em;
background: white;
}
}
Here the nested img rules automatically inherit the header context.
There’s a second candidate for nesting that requires a slightly different syntax. In the code
a {
color: #09c;
text-decoration: none;
}
a:hover {
color: #069;
text-decoration: underline;
}
a:visited {
color: #069;
}
the anchor tag a is repeated with different attributes (hover and visited). The way to reference the parent tag inside nested SCSS is to use the ampersand character &:
a {
color: #09c;
text-decoration: none;
&:hover {
color: #069;
text-decoration: underline;
}
&:visited {
color: #069;
}
}
Variables
Sass allows us to define variables to eliminate duplication and write more expressive code. For example, looking at Listing 5.3, we see that there are repeated references to the same color:
a:hover {
color: #069;
text-decoration: underline;
}
a:visited {
color: #069;
}
In this case, #069 is the color of visited links, so let’s define a variable indicating this purpose:
$visited-link-color: #069;
a:hover {
color: $visited-link-color;
text-decoration: underline;
}
a:visited {
color: $visited-link-color;
}
Because variable names such as $visited-link-color are more descriptive than #069, it’s often useful to define variables even for values that aren’t repeated.
Applying the Sass nesting and variable definition features to the full CSS file gives the SCSS file in Listing 5.14. Note in particular the dramatic improvement in the rules for the nav tag.
app/assets/stylesheets/layout.css.scss
$full-width: 710px;
$background-color: #cff;
$link-color: #09c;
$visited-link-color: #069;
.container {
width: $full-width;
}
body {
background: $background-color;
}
header {
padding-top: 20px;
img {
padding: 1em;
background: white;
}
}
section {
margin-top: 1em;
font-size: 120%;
padding: 20px;
background: white;
h1 {
font-size: 200%;
}
}
/* Links */
a {
color: $link-color;
text-decoration: none;
&:hover {
color: $visited-link-color;
text-decoration: underline;
}
&:visited {
color: $visited-link-color;
}
}
/* Navigation */
nav {
float: right;
background-color: white;
padding: 0 0.7em;
white-space: nowrap;
ul {
margin: 0;
padding: 0;
li {
list-style-type: none;
display: inline-block;
padding: 0.2em 0;
a {
padding: 0 5px;
font-weight: bold;
&:visited {
color: $link-color;
}
&:hover {
text-decoration: underline;
}
}
}
}
}
/* Sign up button */
a.signup_button {
margin-left: auto;
margin-right: auto;
display: block;
text-align: center;
width: 190px;
color: white;
background: #006400;
font-size: 150%;
font-weight: bold;
padding: 20px;
}
/* Round corners */
.round {
-moz-border-radius: 10px;
-webkit-border-radius: 10px;
border-radius: 10px;
}
footer {
text-align: center;
margin-top: 10px;
width: $full-width;
margin-left: auto;
margin-right: auto;
nav {
float: none;
}
}
Sass gives us even more ways to simplify our stylesheets, but the code in Listing 5.14 uses the most important features and gives us a great start. See the Sass website for more detail.
5.3 Layout links
Now that we’ve finished a site layout with decent styling, it’s time to start filling in the links we’ve stubbed out with ’#’. Of course, we could hard-code links like
<a href="/static_pages/about">About</a>
but that isn’t the Rails Way. For one, it would be nice if the URI for the about page were /about rather than /static_pages/about; moreover, Rails conventionally uses named routes, which involves code like
<%= link_to "About", about_path %>
This way the code has a more transparent meaning, and it’s also more flexible since we can change the definition of about_path and have the URI change everywhere about_path is used.
The full list of our planned links appears in Table 5.1, along with their mapping to URIs and routes. We’ll implement all but the last one by the end of this chapter. (We’ll make the last one in Chapter 8.)
| Page | URI | Named route |
|---|---|---|
| Home | / | root_path |
| About | /about | about_path |
| Help | /help | help_path |
| Contact | /contact | contact_path |
| Sign up | /signup | signup_path |
| Sign in | /signin | signin_path |
Before moving on, let’s add a Contact page (left as an exercise in Chapter 3). The test appears as in Listing 5.15, which simply follows the model last seen in Listing 3.18. Note that, as in the application code, in Listing 5.15 we’ve switched to Ruby 1.9–style hashes.
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
.
.
.
describe "Contact page" do
it "should have the h1 'Contact'" do
visit '/static_pages/contact'
page.should have_selector('h1', text: 'Contact')
end
it "should have the title 'Contact'" do
visit '/static_pages/contact'
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Contact")
end
end
end
You should verify that these tests fail:
$ bundle exec rspec spec/requests/static_pages_spec.rb
The application code parallels the addition of the About page in Section 3.2.2: first we update the routes (Listing 5.16), then we add a contact action to the StaticPages controller (Listing 5.17), and finally we create a Contact view (Listing 5.18).
config/routes.rb
SampleApp::Application.routes.draw do
get "static_pages/home"
get "static_pages/help"
get "static_pages/about"
get "static_pages/contact"
.
.
.
end
app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
.
.
.
def contact
end
end
app/views/static_pages/contact.html.erb
<% provide(:title, 'Contact') %>
<h1>Contact</h1>
<p>
Contact Ruby on Rails Tutorial about the sample app at the
<a href="http://railstutorial.org/contact">contact page</a>.
</p>
Now make sure that the tests pass:
$ bundle exec rspec spec/requests/static_pages_spec.rb
5.3.1 Route tests
With the work we’ve done writing integration test for the static pages, writing tests for the routes is simple: we just replace each occurrence of a hard-coded address with the desired named route from Table 5.1. In other words, we change
visit '/static_pages/about'
to
visit about_path
and so on for the other pages. The result appears in Listing 5.19.
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
describe "Home page" do
it "should have the h1 'Sample App'" do
visit root_path
page.should have_selector('h1', text: 'Sample App')
end
it "should have the title 'Home'" do
visit root_path
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Home")
end
end
describe "Help page" do
it "should have the h1 'Help'" do
visit help_path
page.should have_selector('h1', text: 'Help')
end
it "should have the title 'Help'" do
visit help_path
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Help")
end
end
describe "About page" do
it "should have the h1 'About'" do
visit about_path
page.should have_selector('h1', text: 'About Us')
end
it "should have the title 'About Us'" do
visit about_path
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | About Us")
end
end
describe "Contact page" do
it "should have the h1 'Contact'" do
visit contact_path
page.should have_selector('h1', text: 'Contact')
end
it "should have the title 'Contact'" do
visit contact_path
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Contact")
end
end
end
As usual, you should check that the tests are now red:
$ bundle exec rspec spec/requests/static_pages_spec.rb
By the way, if the code in Listing 5.19 strikes you as repetitive and verbose, you’re not alone. We’ll refactor this mess into a beautiful jewel in Section 5.3.4.
5.3.2 Rails routes
Now that we have tests for the URIs we want, it’s time to get them to work. As noted in Section 3.1.2, the file Rails uses for URI mappings is config/routes.rb. If you take a look at the default routes file, you’ll see that it’s quite a mess, but it’s a useful mess—full of commented-out example route mappings. I suggest reading through it at some point, and I also suggest taking a look at the Rails Guides article “Rails Routing from the outside in” for a much more in-depth treatment of routes.
To define the named routes, we need to replace rules such as
get 'static_pages/help'
with
match '/help', to: 'static_pages#help'
This arranges both for a valid page at /help and a named route called help_path that returns the path to that page. (Actually, using get in place of match gives the same named routes, but using match is more conventional.)
Applying this pattern to the other static pages gives Listing 5.20. The only exception is the Home page, which we’ll take care of in Listing 5.22.
config/routes.rb
SampleApp::Application.routes.draw do
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
.
.
.
end
If you read the code in Listing 5.20 carefully, you can probably figure out what it does; for example, you can see that
match '/about', to: 'static_pages#about'
matches ’/about’ and routes it to the about action in the StaticPages controller. Before, this was more explicit: we used get ’static_pages/about’ to get to the same place, but /about is more succinct. In addition, as mentioned above, the code match ’/about’ also automatically creates named routes for use in the controllers and views:
about_path => '/about'
about_url => 'http://localhost:3000/about'
Note that about_url is the full URI http://localhost:3000/about (with localhost:3000 being replaced with the domain name, such as example.com, for a fully deployed site). As discussed in Section 5.3, to get just /about, you use about_path. (The Rails Tutorial uses the path form for consistency, but the difference rarely matters in practice.)
With these routes now defined, the tests for the Help, About, and Contact pages should pass:
$ bundle exec rspec spec/requests/static_pages_spec.rb
(If you are running Spork, you will probably have to restart it to get the tests to pass.) This leaves the test for the Home page as the last one to fail.
To establish the route mapping for the Home page, we could use code like this:
match '/', to: 'static_pages#home'
This is unnecessary, though; Rails has special instructions for the root URI / (“slash”) located lower down in the file (Listing 5.21).
config/routes.rb
SampleApp::Application.routes.draw do
.
.
.
# You can have the root of your site routed with "root"
# just remember to delete public/index.html.
# root :to => "welcome#index"
.
.
.
end
Using Listing 5.21 as a model, we arrive at Listing 5.22 to route the root URI / to the Home page.
config/routes.rb
SampleApp::Application.routes.draw do
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
root to: 'static_pages#home'
.
.
.
end
This code maps the root URI / to /static_pages/home, and also gives URI helpers as follows:
root_path => '/'
root_url => 'http://localhost:3000/'
We should also heed the comment in Listing 5.21 and delete public/index.html to prevent Rails from rendering the default page (Figure 1.3) when we visit /. You can of course simply remove the file by trashing it, but if you’re using Git for version control there’s a way to tell Git about the removal at the same time using git rm:
$ git rm public/index.html
You may recall from Section 1.3.5 that we used the Git command git commit -a -m "Message", with flags for “all changes” (-a) and a message (-m). As shown above, Git also lets us roll the two flags into one using git commit -am "Message".
With that, all of the routes for static pages are working, and the tests should pass:
$ bundle exec rspec spec/requests/static_pages_spec.rb
(As before, Spork users will have to re-start the Spork server.) Now we just have to fill in the links in the layout.
5.3.3 Named routes
Let’s put the named routes created in Section 5.3.2 to work in our layout. This will entail filling in the second arguments of the link_to functions with the proper named routes. For example, we’ll convert
<%= link_to "About", '#' %>
to
<%= link_to "About", about_path %>
and so on.
We’ll start in the header partial, _header.html.erb (Listing 5.23), which has links to the Home and Help pages. While we’re at it, we’ll follow a common web convention and link the logo image to the Home page as well.
app/views/layouts/_header.html.erb
<header>
<% logo = image_tag("logo.png", alt: "Sample App", class: "round") %>
<%= link_to logo, root_path %>
<nav class="round">
<ul>
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</header>
We won’t have a named route for the “Sign in” link until Chapter 8, so we’ve left it as ’#’ for now. Note that this code defines the local variable logo for the logo image tag, and then links to it in the next line:
<% logo = image_tag("logo.png", alt: "Sample App", class: "round") %>
<%= link_to logo, root_path %>
This is a little cleaner than stuffing it all into one line. It’s especially important to notice that the ERb for the variable assignment doesn’t have an equals sign; it’s just <% ... %>, because we don’t want that line inserted into the template. (Using a local variable in this manner is only one way to do it. An even cleaner way might be to define a logo helper; see Section 5.6.)
The other place with links is the footer partial, _footer.html.erb, which has links for the About and Contact pages (Listing 5.24).
app/views/layouts/_footer.html.erb
<footer>
<nav class="round">
<ul>
<li><%= link_to "About", about_path %></li>
<li><%= link_to "Contact", contact_path %></li>
<li><a href="http://news.railstutorial.org/">News</a></li>
<li><a href="http://railstutorial.org/">Rails Tutorial</a></li>
</ul>
</nav>
</footer>
With that, our layout has links to all the static pages created in Chapter 3, so that, for example, /about goes to the About page (Figure 5.9).
By the way, it’s worth noting that, although we haven’t actually tested for the presence of the links on the layout, our tests will fail if the routes aren’t defined. You can check this by commenting out the routes in Listing 5.20 and running your test suite. For a testing method that actually makes sure the links go to the right places, see Section 5.6.

5.3.4 Pretty RSpec
We noted in Section 5.3.1 that the tests for the static pages are getting a little verbose and repetitive (Listing 5.19). In this section we’ll make use of the latest features of RSpec to make our tests more compact and elegant.
Let’s take a look at a couple of the examples to see how they can be improved:
describe "Home page" do
it "should have the h1 'Sample App'" do
visit root_path
page.should have_selector('h1', text: 'Sample App')
end
it "should have the title 'Home'" do
visit root_path
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Home")
end
end
One thing we notice is that both examples include a visit to the root path. We can eliminate this duplication with a before block:
describe "Home page" do
before { visit root_path }
it "should have the h1 'Sample App'" do
page.should have_selector('h1', text: 'Sample App')
end
it "should have the title 'Home'" do
page.should have_selector('title',
text: "Ruby on Rails Tutorial Sample App | Home")
end
end
This uses the line
before { visit root_path }
to visit the root path before each example. (The before method can also be invoked with before(:each), which is a synonym.)
Another source of duplication appears in each example; we have both
it "should have the h1 'Sample App'" do
and
page.should have_selector('h1', text: 'Sample App')
which say essentially the same thing. In addition, both examples reference the page variable. We can eliminate these sources of duplication by telling RSpec that page is the subject of the tests using
subject { page }
and then using a variant of the it method to collapse the code and description into one line:
it { should have_selector('h1', text: 'Sample App') }
Because of subject { page }, the call to should automatically uses the page variable supplied by Capybara (Section 3.2.1).
Applying these changes gives much more compact tests for the Home page:
subject { page }
describe "Home page" do
before { visit root_path }
it { should have_selector('h1', text: 'Sample App') }
it { should have_selector 'title',
text: "Ruby on Rails Tutorial Sample App | Home" }
end
This code looks nicer, but the title test is still a bit long. Indeed, all of the title tests in Listing 5.19 have long title text of the form
"Ruby on Rails Tutorial Sample App | Home"
An exercise in Section 3.5 proposes eliminating some of this duplication by defining a base_title variable and using string interpolation (Listing 3.30). We can do even better by defining a utility function for full_title, which parallels the full_title helper from Listing 4.2. (See if you can figure out why we don’t just use the full_title helper itself. Hint: What if there were a typo in the base title?) We do this by creating both a spec/support directory and a utilities.rb file for RSpec utilities (Listing 5.25).
full_title function. spec/support/utilities.rb
def full_title(page_title)
base_title = "Ruby on Rails Tutorial Sample App"
if page_title.empty?
base_title
else
"#{base_title} | #{page_title}"
end
end
Files in the spec/support directory are automatically included by RSpec, which means that we can write the Home tests as follows:
subject { page }
describe "Home page" do
before { visit root_path }
it { should have_selector('h1', text: 'Sample App') }
it { should have_selector('title', text: full_title('Home')) }
end
We can now simplify the tests for the Help, About, and Contact pages using the same methods used for the Home page. The results appear in Listing 5.26.
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
subject { page }
describe "Home page" do
before { visit root_path }
it { should have_selector('h1', text: 'Sample App') }
it { should have_selector('title', text: full_title('Home')) }
end
describe "Help page" do
before { visit help_path }
it { should have_selector('h1', text: 'Help') }
it { should have_selector('title', text: full_title('Help')) }
end
describe "About page" do
before { visit about_path }
it { should have_selector('h1', text: 'About') }
it { should have_selector('title', text: full_title('About Us')) }
end
describe "Contact page" do
before { visit contact_path }
it { should have_selector('h1', text: 'Contact') }
it { should have_selector('title', text: full_title('Contact')) }
end
end
You should now verify that the tests still pass (Spork users may have to restart the Spork server):
$ bundle exec rspec spec/requests/static_pages_spec.rb
This RSpec style in Listing 5.26 is much pithier than the style in Listing 5.19—indeed, it can be made even pithier (Section 5.6). We will use this more compact style whenever possible when developing the rest of the sample application.
5.4 User signup: A first step
As a capstone to our work on the layout and routing, in this section we’ll make a route for the signup page, which will mean creating a second controller along the way. This is a first important step toward allowing users to register for our site; we’ll take the next step, modeling users, in Chapter 6, and we’ll finish the job in Chapter 7.
5.4.1 Users controller
It’s been a while since we created our first controller, the StaticPages controller, way back in Section 3.1.2. It’s time to create a second one, the Users controller. As before, we’ll use generate to make the simplest controller that meets our present needs, namely, one with a stub signup page for new users. Following the conventional REST architecture favored by Rails, we’ll call the action for new users new and pass it as an argument to generate controller to create it automatically (Listing 5.27).
new action). $ rails generate controller Users new --no-test-framework
create app/controllers/users_controller.rb
route get "users/new"
invoke erb
create app/views/users
create app/views/users/new.html.erb
invoke helper
create app/helpers/users_helper.rb
invoke assets
invoke coffee
create app/assets/javascripts/users.js.coffee
invoke scss
create app/assets/stylesheets/users.css.scss
This creates a Users controller with a new action (Listing 5.28) and a stub user view (Listing 5.29).
new action. app/controllers/users_controller.rb
class UsersController < ApplicationController
def new
end
end
new action for Users. app/views/users/new.html.erb
<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>
5.4.2 Signup URI
With the code from Section 5.4.1, we already have a working page for new users at /users/new, but recall from Table 5.1 that we want the URI to be /signup instead. As in Section 5.3, we’ll first write some integration tests, which we’ll now generate:
$ rails generate integration_test user_pages
Then, following the model of the static pages spec in Listing 5.26, we’ll fill in the user pages test with code to test for the contents of the h1 and title tags, as seen in Listing 5.30.
spec/requests/user_pages_spec.rb
require 'spec_helper'
describe "User pages" do
subject { page }
describe "signup page" do
before { visit signup_path }
it { should have_selector('h1', text: 'Sign up') }
it { should have_selector('title', text: full_title('Sign up')) }
end
end
We can run these tests using the rspec command as usual:
$ bundle exec rspec spec/requests/user_pages_spec.rb
It’s worth noting that we can also run all the request specs by passing the whole directory instead of just one file:
$ bundle exec rspec spec/requests/
Based on this pattern, you may be able to guess how to run all the specs:
$ bundle exec rspec spec/
For completeness, we’ll usually use this method to run the tests through the rest of the tutorial. By the way, it’s worth noting (since you may see other people use it) that you can also run the test suite using the spec Rake task:
$ bundle exec rake spec
(In fact, you can just type rake by itself; the default behavior of rake is to run the test suite.)
By construction, the Users controller already has a new action, so to get the test to pass all we need is the right route and the right view content. We’ll follow the examples from Listing 5.20 and add a match ’/signup’ rule for the signup URI (Listing 5.31).
config/routes.rb
SampleApp::Application.routes.draw do
get "users/new"
match '/signup', to: 'users#new'
match '/help', to: 'static_pages#help'
match '/about', to: 'static_pages#about'
match '/contact', to: 'static_pages#contact'
root to: 'static_pages#home'
.
.
.
end
Note that we have kept the rule get "users/new", which was generated automatically by the Users controller generation in Listing 5.27. Currently, this rule is necessary for the ’users/new’ routing to work, but it doesn’t follow the proper REST conventions (Table 2.2), and we will eliminate it in Section 7.1.2.
To get the tests to pass, all we need now is a view with the title and heading “Sign up” (Listing 5.32).
app/views/users/new.html.erb
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<p>Find me in app/views/users/new.html.erb</p>
At this point, the signup test in Listing 5.30 should pass. All that’s left is to add the proper link to the button on the Home page. As with the other routes, match ’/signup’ gives us the named route signup_path, which we put to use in Listing 5.33.
app/views/static_pages/home.html.erb
<% provide(:title, 'Home') %>
<h1>Sample App</h1>
<p>
This is the home page for the
<a href="http://railstutorial.org/">Ruby on Rails Tutorial</a>
sample application.
</p>
<%= link_to "Sign up now!", signup_path, class: "signup_button round" %>
With that, we’re done with the links and named routes, at least until we add a route for signing in (Chapter 8). The resulting new user page (at the URI /signup) appears in Figure 5.10.

At this point the tests should pass:
$ bundle exec rspec spec/
5.4.3 Deploying to production with Blueprint
Having fleshed out our sample site a bit, now is a good time to deploy the application to the production server. Because of the addition of third-party CSS in Section 4.1.2, we need to take an additional step to deploy the application to production. In particular, the Blueprint CSS works fine in a development environment, but it won’t work in production without additional configuration.
The first step to a successful deployment is to merge the changes back into the master branch:
$ git add .
$ git commit -m "Finish layout and routes"
$ git checkout master
$ git merge filling-in-layout
To get the deployment to work, we need to tell the asset pipeline about Blueprint CSS. This involves editing the production.rb file in config/environments, the configuration file that Rails uses in a production environment. The result appears in Listing 5.34.
config/environments/production.rb
SampleApp::Application.configure do
.
.
.
# Precompile Blueprint CSS
config.assets.precompile += [ "blueprint/*.css" ]
end
The last line in Listing 5.34 adds an array containing a string to the list of elements to be precompiled; the pattern blueprint/*.css matches all the CSS in the blueprint directory. (Rails automatically looks in each of app/assets, lib/assets, and vendor/assets, in this case finding the blueprint directory in the last of the three.)
To get the production site working, we have to commit the change to the configuration file and push the result up to Heroku:
$ git commit -am "Precompile Blueprint CSS in production"
$ git push heroku
The result of all this work should be a working sample application on the production server:
$ heroku open
If you run into trouble, try running
$ heroku logs
to debug the error using the Heroku logfile.
5.5 Conclusion
In this chapter, we’ve hammered our application layout into shape and polished up the routes. The rest of the book is dedicated to fleshing out the sample application: first, by adding users who can sign up, sign in, and sign out; next, by adding user microposts; and, finally, by adding user following.
5.6 Exercises
- Replace the local variable
logoin Listing 5.23 with a helper method of the same name, so that the new partial looks like Listing 5.35. Use the code in Listing 5.37 to help you get started. - The code in Listing 5.26 for testing static pages is compact but is still a bit repetitive. RSpec supports a facility called shared examples to eliminate the kind of duplication. By following the example in Listing 5.36, fill in the missing tests for the Help, About, and Contact pages. Note that the
letcommand, introduced briefly in Listing 3.30, creates a local variable with the given value on demand (i.e., when the variable is used), in contrast to an instance variable, which is created upon assignment. - You may have noticed that our tests for the layout links test the routing but don’t actually check that the links on the layout go to the right pages. One way to implement these tests is to use
visitandclick_linkinside the RSpec integration test. Fill in the code in Listing 5.38 to verify that all the layout links are properly defined.
app/views/layouts/_header.html.erb
<header>
<%= link_to logo, root_path %>
<nav class="round">
<ul>
<li><%= link_to "Home", root_path %></li>
<li><%= link_to "Help", help_path %></li>
<li><%= link_to "Sign in", '#' %></li>
</ul>
</nav>
</header>
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
subject { page }
shared_examples_for "all static pages" do
it { should have_selector('h1', text: heading) }
it { should have_selector('title', text: full_title(page_title)) }
end
describe "Home page" do
before { visit root_path }
let(:heading) { 'Sample App' }
let(:page_title) { 'Home' }
it_should_behave_like "all static pages"
end
describe "Help page" do
.
.
.
end
describe "About page" do
.
.
.
end
describe "Contact page" do
.
.
.
end
end
logo helper. app/helpers/application_helper.rb
module ApplicationHelper
def logo
# Fill in.
end
# Returns the full title on a per-page basis.
def full_title(page_title)
.
.
.
end
end
spec/requests/static_pages_spec.rb
require 'spec_helper'
describe "Static pages" do
.
.
.
it "should have the right links on the layout" do
visit root_path
click_link "About"
page.should have_selector 'title', text: full_title('About Us')
click_link "Help"
page.should # fill in
click_link "Contact"
page.should # fill in
click_link "Home"
page.should # fill in
click_link "Sign up now!"
page.should # fill in
end
end
- The mockups in the Ruby on Rails Tutorial are made with an excellent online mockup application called Mockingbird. ↑
- These are completely unrelated to Ruby classes. ↑
- You might notice that the
imgtag, rather than looking like <img>...</img>, instead looks like <img ... />. Tags that follow this form are known as self-closing tags. ↑ - The
alttext is also what will be displayed by screen readers for the visually impaired. Though people are sometimes sloppy about including thealtattribute for images, it is in fact required by the HTML standard. Luckily, Rails includes a defaultaltattribute; if you don’t specify the attribute in the call toimage_tag, Rails just uses the image filename (minus extension). In this case, though,Sample Appis more descriptive thanlogo, so I’ve elected to set thealttext explicitly. ↑ - Note that Safari and Chrome users will see an indicator of a broken image in place of the “Sample App” alt text. ↑
- HTML colors can be coded with three base-16 (hexadecimal) numbers, one each for the primary colors red, green, and blue. The code
#fffmaxes out all three colors, yielding pure white, but the CSS standard defineswhiteas a synonym. See this HTML colors site for more information. ↑ - Blueprint CSS uses a grid of columns 40 pixels across, 30 pixels for the column itself and 10 pixels of padding. The rightmost column doesn’t need padding, so 18 columns is 710 pixels: 18 * 40 – 10 = 710. ↑
- Many Rails developers use a
shareddirectory for partials shared across different views. I prefer to use thesharedfolder for utility partials that are useful on multiple views, while putting partials that are literally on every page (as part of the site layout) in thelayoutsdirectory. (We’ll create theshareddirectory starting in Chapter 7.) That seems to me a logical division, but putting them all in thesharedfolder certainly works fine, too. ↑ - The structure of this section is based on the excellent blog post The Rails 3 Asset Pipeline in (about) 5 Minutes by Michael Erasmus. For more details, see the Rails Guide on the Asset Pipeline. ↑
- The older
.sassformat, also supported by Sass, defines a new language which is less verbose (and has fewer curly braces) but is less convenient for existing projects and is harder to learn for those already familiar with CSS. ↑





