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 and viewing users, part I
- Chapter 7 Modeling and viewing users, part II
- Chapter 8 Sign up
- Chapter 9 Sign in, sign out
- Chapter 10 Updating, showing, and deleting users
- Chapter 11 User microposts
- Chapter 12 Following users
- Chapter 13 Rails 3.1
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 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 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
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 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 a programmer, educator, and entrepreneur. Michael was coauthor of RailsSpace, a best-selling Rails tutorial book published in 2007, and was cofounder and lead developer of Insoshi, a popular social networking platform in Ruby on Rails. Previously, he taught theoretical and computational physics at the California Institute of Technology (Caltech), where he received the Lifetime Achievement Award for Excellence in Teaching. Michael 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 © 2010 by Michael Hartl. All source code in Ruby on Rails Tutorial is available under the MIT License and the Beerware License.
Copyright (c) 2010 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 13 Rails 3.1
Even seven years after its initial release, Ruby on Rails continues to be on the cutting edge of web application development, and each new version of Rails includes features that make Rails applications more powerful and Rails application developers more productive. Rails 3.1—available as a release candidate as of this writing—is no exception. This chapter provides a description of how to upgrade the Rails Tutorial sample application from Rails 3.0 to Rails 3.1 (Section 13.1), as well as a brief overview of some of the more interesting new features in Rails 3.1 (Section 13.2).
As noted in Section 1.2.2.5, there are a few backwards-incompatible changes in Rails 3.1, several of which affect the sample application. Principal among these are a new convention for the placement of images, stylesheets, and JavaScript files—collectively known as assets—and a change in the default JavaScript library from Prototype to jQuery. Section 13.1.4 discusses these changes in more depth.
Rails 3.1 also includes some changes that, while compatible with Rails 3.0 applications, will nevertheless affect the development of applications in the future. These new features include reversible migrations and the inclusion of Sass and CoffeeScript as new defaults. A brief overview of these changes, and pointers to more detailed resources, appear in Section 13.2.
Finally, a future edition of this book (and a new version of the accompanying screencasts) will use Rails 3.1 (or a more up-to-date version if available) from the beginning. I plan to cover both Sass and CoffeeScript, as well as some of the changes in other parts of the Ruby and Rails ecosystems (such as improved RSpec syntax) that will be valuable to beginning Rails developers. Subscribe to the Rails Tutorial news feed to be notified when the new edition is available.
With every new Rails release, there is a time delay while the rest of the ecosystem catches up. For example, as of this writing, Rails 3.1 application deployment to Heroku is not yet supported, and (as discussed in Section 13.1.3) the will_paginate gem is broken. This is the price we pay for being on the bleeding edge—sometimes we get cut.
13.1 Upgrading the sample app
Our first step in getting a handle on Rails 3.1 is to upgrade the sample application developed in Chapter 3 through Chapter 12. There are two possible strategies for accomplishing this. The first is to edit the sample application directly, changing the Gemfile and the configuration files, and then dealing with any breakage that ensues. Some online resources to help with this approach are Helpful resources for upgrading to Rails 3.1 and How to upgrade a Rails application to version 3.1.0. In this chapter, we’ll take a second approach, which is to create a new Rails 3.1 application from scratch, and then copy over files one by one from the existing sample application until we get the new application to work.
There are several advantages to this second approach. For one, because we will generate the initial application using rails new, the Gemfile and configuration files will automatically be configured correctly for Rails 3.1. In addition, by adding one file at a time (or, at most, a few) we can more easily isolate the source of any breakage. The downside is that we might forget a file or two, leading to a broken application, although this is unlikely because of our thorough test suite. Ultimately, the right strategy probably depends on the exact nature of the app; in my judgment, the best way to upgrade the sample application is using this second strategy, but you are free to try the first.
For a more detailed treatment of the topics in this section, please see the Ruby on Rails Tutorial screencasts, which now include a bonus Lesson 13 on Rails 3.1. Among other things, after completing the full Rails 3.1 upgrade, the screencast shows how to create a dedicated rails-3-1 branch in the main sample app’s Git repository. As a result, if you want to compare your work to the book’s sample application code, you can find the rails-3-1 branch at GitHub.
13.1.1 Installing and configuring Rails 3.1
To get started with the Rails 3.1 upgrade, it is a good idea to create a dedicated gemset if you are using Ruby Version Manager (RVM):
$ rvm --create use 1.9.2@rails3_1tutorial
Whether you’re using RVM or not, you will need to install Rails 3.1:
$ gem install rails --version 3.1.0
(If you get a permissions error here, recall from Section 1.1.3 that you may have to use sudo.)
Once you have installed Rails, you can verify that you have the right version as follows:
$ rails -v
Rails 3.1.0
Then create a dedicated Rails 3.1 sample app skeleton:
$ cd ~/rails_projects
$ rails new sample_app_3_1
Finally, add the application-specific gems from Listing 10.42 to the default Rails 3.1 Gemfile, yielding Listing 13.1. (Note that you must use version 1.3.4 of the sqlite3 gem; 1.3.3 won’t work.)
Gemfile needed for Rails 3.1.
source 'http://rubygems.org'
gem 'rails', '3.1.0'
gem 'gravatar_image_tag', '1.0.0.pre2'
gem 'will_paginate', '3.0.pre2'
gem 'sqlite3', '1.3.4'
# Asset template engines
gem 'sass-rails', "~> 3.1.0.rc"
gem 'coffee-script'
gem 'uglifier'
gem 'jquery-rails'
group :development do
gem 'rspec-rails', '2.6.1'
gem 'annotate', '2.4.0'
gem 'faker', '0.3.1'
end
group :test do
gem 'rspec-rails', '2.6.1'
gem 'webrat', '0.7.1'
gem 'spork', '0.9.0.rc5'
gem 'factory_girl_rails', '1.0'
end
Of course, before proceeding you should install the gems as well:
$ bundle install
13.1.2 Getting to Red
Having made a minimal skeleton Rails 3.1 app in Section 13.1.1, we’re now ready to get the sample app working. As mentioned in the introduction to this section, our basic strategy is to copy over one file at a time; one possibility is to use the OS X Finder app (or the equivalent application on your system), as shown in Figure 13.1.

The upgrade strategy in the companion screencast to this section is to copy over a single spec file, spec/controllers/pages_controller_spec.rb, and then try to get it to pass. After copying over the file, we initialize RSpec as in Chapter 3:
$ rails generate rspec:install
If you are using RSpec 2.5, this step will fail, as Rails 3.1 requires version 2.6.1 of the rspec-rails gem. If you use the Gemfile in Listing 13.1, this won’t be a problem, but previous versions of this book used an earlier (and incompatible) version of the gem.
Next, try running the test suite:
$ bundle exec rspec spec/
It will be Red initially, and our upgrade strategy is to analyze the error message and copy over files until the test suite passes. Once the partial test suite is Green, copy over the other tests in small groups, watch them fail, and then get them to pass. Lather, rinse, repeat.
Although the rest of this section covers some changes you will definitely have to make to get the application to work, this chapter doesn’t cover all the details of the upgrade process, which in any case will vary by system. By the nature of this subject, it’s easier to show the upgrade steps in a screencast, but if you have gotten this far in the Ruby on Rails Tutorial then you are probably up to the challenge posed by doing the upgrade yourself (Section 13.3).
13.1.3 Minor issues
When upgrading the sample app, you will encounter some (rather annoying) minor issues. This section mentions some of the problems I ran into (together with solutions), but of course YMMV.
will_paginate
In the process of trying to get from Red to Green, you will discover that the will_paginate gem is incompatible with Rails 3.1, yielding an error that looks like this:
uninitialized constant
ActiveRecord::Associations::AssociationCollection (NameError)
The solution (obtained by Googling the error message) is, quite unfortunately, to edit the will_paginate gem source code directly. This requires finding the source on your system, which might be tricky; on my system, it looks like this:
$ cd ~/.rvm/gems/ruby-1.9.2-p180@rails3_1tutorial/gems/
$ mate will_paginate-3.0.pre2/lib/will_paginate/finders/active_record.rb
The fix is simple: we need to replace AssociationCollection to CollectionAssociation, as shown in the diff in Listing 13.2. (I have omitted a reference to ::ActiveRecord::Relation to save on space, but you should leave it in.)
This change is a terrible kludge—among other things, it will break if we ever reinstall the will_paginate gem, and it will fail in production—but it works for now, and presumably this issue will be fixed in a future release of will_paginate.1
# support pagination on associations and scopes
- [::ActiveRecord::Associations::AssociationCollection].each do |klass|
+ [::ActiveRecord::Associations::CollectionAssociation].each do |klass|
klass.send(:include, ActiveRecord)
end
end
Pagination spec
Another minor issue you may encounter is a failing pagination test. This is apparently due to a change in the way Rails 3.1 constructs URLs compared to Rails 3.0, and one rather hackish solution is simply to remove the URL specificity from the test, as shown in Listing 13.3.
spec/controllers/users_controller_spec.rb
get :index
response.should have_selector('div.pagination')
response.should have_selector('span.disabled', :content => "Previous")
- response.should have_selector('a', :href => "/users?page=2",
- :content => "2")
- response.should have_selector('a', :href => "/users?page=2",
- :content => "Next")
+ response.should have_selector('a', :content => "2")
+ response.should have_selector('a', :content => "Next")
end
it "should have delete links for admins" do
After making this change, and copying over all the files from your main sample app, your test suite might even move from Red to Green. If it doesn’t, keep iterating and Googling error messages until it does. (You might also consider the resources on the Rails Tutorial Help page.)
13.1.4 Major differences
The “major” differences between the Rails 3.0 and Rails 3.1 sample apps aren’t really that big—it’s just that they affect virtually all Rails applications. In this section, we’ll see how to incorporate these differences to complete our new Rails 3.1 sample application.
Asset directories
The biggest practical difference between Rails 3.0 and Rails 3.1 apps is a change in the location of asset files such as images, stylesheets, and JavaScript files. In previous versions of Rails, these files all lived in the public/ directory:
public/images/
public/stylesheets/
public/javascripts/
In Rails 3.1, the location of these files differs based on whether they are created by us or come from an external vendor. In the case of images we make or code we write, the files live in the app/assets directory:
app/assets/images/
app/assets/stylesheets/
app/assets/javascripts/
In the case of code or images from external vendors, we use the vendor/assets directory:
vendor/assets/images/
vendor/assets/stylesheets/
vendor/assets/javascripts/
For the sample app, the above discussion means placing the public/stylesheets/custom.css file in app/assets/stylesheets/ and the logo image public/images/logo.png in app/assets/images/, while placing the public/stylesheets/blueprint/ CSS directory in vendor/assets/stylesheets. These require minor changes to the layout file and stylesheets partial, as shown in Listing 13.4 and Listing 13.5.
app/views/layouts/application.html.erb.
<title><%= title %></title>
<%= csrf_meta_tag %>
<%= render 'layouts/stylesheets' %>
- <%= javascript_include_tag :defaults %>
+ <%= stylesheet_link_tag "application" %>
+ <%= javascript_include_tag "application" %>
</head>
<body>
<div class="container">
app/views/layouts/_stylesheets.html.erb.
<![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 'custom', :media => 'screen' %>
Note that both the stylesheet and JavaScript includes use the form
<%= <type>_tag "application" %>
where the argument is the string "application". In the case of CSS, the application file will be application.css; in the case of JavaScript, it will be application.js. In both cases, the application files are generated for us by Rails, so that (for example) the contents of custom.css will be included automatically as part of application.css. These features are part of the asset pipeline, which is new in Rails 3.1, and is discussed in more detail in Section 13.2.1.
Prototype to jQuery
The second big change in Rails 3.1 that affects a large number of apps is the change from Prototype to jQuery as the default JavaScript library. Of course, it is easy to switch back—just change jquery-rails to prototype-rails in the Gemfile (Listing 13.1)—but jQuery has high adoption rates among Rails developers, and making it the default has been a long time coming.
In the case of the sample application, the only functionality affected by the Prototype-to-jQuery switch is the Ajax in the follow/unfollow button covered in Section 12.2.5. The principal syntactic difference is that, where Prototype writes
$("follow_form")
to manipulate the follow_form CSS id, jQuery writes
$("#follow_form")
instead. This jQuery syntax, inspired by CSS, uses the # symbol to indicate a CSS id. (As you might guess, jQuery, like CSS, uses a dot . to manipulate CSS classes.) The resulting changes to the Ajax create and destroy files are shown in Listing 13.6 and Listing 13.7, while the updated code itself appears in Listing 13.8 and Listing 13.9. Note that, in addition to having a different syntax for manipulating the DOM, jQuery uses the html method to modify the contents of an HTML element where Prototype uses update.
create.js.erb.
- $("follow_form").update("<%= escape_javascript(render('users/unfollow')) %>")
- $("followers").update('<%= "#{@user.followers.count} followers" %>')
+ $("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
+ $("#followers").html('<%= "#{@user.followers.count} followers" %>')
destroy.js.erb.
- $("follow_form").update("<%= escape_javascript(render('users/follow')) %>")
- $("followers").update('<%= "#{@user.followers.count} followers" %>')
+ $("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
+ $("#followers").html('<%= "#{@user.followers.count} followers" %>')
app/views/relationships/create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= "#{@user.followers.count} followers" %>')
app/views/relationships/destroy.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/follow')) %>")
$("#followers").html('<%= "#{@user.followers.count} followers" %>')
With these changes, and the changes to the asset locations from Section 13.1.4.1, the new sample app should be complete and fully compatible with Rails 3.1. (Don’t forget—as I did in the Rails 3.1 upgrade screencast—to rename the README and replace it with the README.markdown from Listing 3.2.)
13.2 New features in Rails 3.1
Rails 3.1 contains some exciting new features, but it’s important to emphasize that most of them are either automatic (included for free by Rails) or are optional. For an overview of the changes in Rails 3.1, the post Rails 3.1: Release candidate is a good place to start. This section discusses a few of them in more detail.
13.2.1 Asset pipeline
One of the most exciting Rails 3.1 features is the asset pipeline, which Rails creator David Heinemeier Hansson discussed in his keynote at RailsConf 2011. The asset pipeline is a suite of technologies designed to make the deployment of assets—i.e., images, stylesheets, and JavaScript—more efficient and convenient. For example, all stylesheets and JavaScript files are concatenated automatically and served as single files in production. (The changes described in Section 13.1.4.1 are the necessary prerequisites to using the asset pipeline.) To learn about the details, see the Railscast Rails 3.1 Overview and Ville Lautanala’s post on the Rails 3.1 Asset Pipeline in the Real World. A future edition of this book will integrate the asset pipeline from the beginning.
13.2.2 Reversible migrations
Rails 3.1 also introduces reversible migrations, which allow Rails to infer the up and down methods used to migrate the database up and down. For example, the migration in Listing 6.2, reproduced below as Listing 13.10, can in Rails 3.1 appear as in Listing 13.11.
users table). db/migrate/<timestamp>_create_users.rb
class CreateUsers < ActiveRecord::Migration
def self.up
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
def self.down
drop_table :users
end
end
class CreateUsers < ActiveRecord::Migration
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
In the case of Listing 13.11, Rails uses the change method to construct the appropriate up and down migrations on the fly.
Of course, not all migrations can be inferred in this manner, so Rails 3.1 still allows developers to define their own up and down methods. Indeed, migrations are backwards-compatible, so the migration code from previous chapters will still work. Of course, a future edition of this book will generate migrations using Rails 3.1 (or its successor), and hence will include reversible migrations as a matter of course.
13.2.3 Sass and CoffeeScript
Finally, by default Rails 3.1 includes Sass, which is a language for creating “Syntactically awesome stylesheets”, and CoffeeScript, which is a syntactically elegant language that compiles into JavaScript. For good introductions to each, see the Railscast on CoffeeScript Basics and the Railscast on Sass Basics.
At first glance, these new defaults seem like a big change to the way Rails applications are developed, and several commentators have expressed concern that the addition of Sass and CoffeeScript make Rails more difficult to learn. In this context, it is essential to understand that using Sass or CoffeeScript in Rails 3.1 applications is optional. Every valid CSS file is also a valid Sass file, so if you don’t want to use Sass, you don’t have to. Similarly, while you can write CoffeeScript if you want to, JavaScript is still fully supported: .js files in app/assets/javascripts or vendor/assets/javascripts will be included in the concatenated application.js file that is part of the Rails 3.1 asset pipeline.
In other words, vanilla CSS and JavaScript will always work, so there is no cause for alarm. On the other hand, Sass and CoffeeScript are awesome (there’s a reason they’re now part of the default installation), and in a future edition of this book I plan to cover them in more depth.
13.3 Exercises
- Complete the upgrade started in Section 13.1 if you haven’t already. Don’t give up until your test suite is Green and the application (running locally) looks and behaves correctly.
- (hard) Rails 3.1 supports roll-your-own authentication with a new method called
has_secure_password. Starting with the Railscast on Authentication in Rails 3.1, refactor the authentication framework from Chapter 7 to use the new features of Rails 3.1. (Naturally, a future edition of this book will include these new features from the start.)
- To use the modified gem in production at Heroku, we would have to build our own gem based on a fork of will_paginate. Since the fix is so easy, I’d guess this issue will be fixed by the time Heroku fully supports Rails 3.1. ↑




