Ruby on Rails Tutorial
Learn Rails by Example
- Chapter 1 From zero to deploy
- 1.1 Introduction
- 1.2 Up and running
- 1.3 Version control with Git
- 1.4 Deploying
- 1.5 Conclusion
- Chapter 2 A demo app
- 2.1 Planning the application
- 2.2 The Users resource
- 2.3 The Microposts resource
- 2.4 Conclusion
- Chapter 3 Mostly static pages
- 3.1 Static pages
- 3.2 Our first tests
- 3.3 Slightly dynamic pages
- 3.4 Conclusion
- 3.5 Exercises
- Chapter 4 Rails-flavored Ruby
- 4.1 Motivation
- 4.2 Strings and methods
- 4.3 Other data structures
- 4.4 Ruby classes
- 4.5 Exercises
- Chapter 5 Filling in the layout
- Chapter 6 Modeling and viewing users, part I
- 6.1 User model
- 6.2 User validations
- 6.3 Viewing users
- 6.4 Conclusion
- 6.5 Exercises
- Chapter 7 Modeling and viewing users, part II
- 7.1 Insecure passwords
- 7.2 Secure passwords
- 7.3 Better user views
- 7.4 Conclusion
- 7.5 Exercises
- Chapter 8 Sign up
- 8.1 Signup form
- 8.2 Signup failure
- 8.3 Signup success
- 8.4 RSpec integration tests
- 8.5 Conclusion
- 8.6 Exercises
- Chapter 9 Sign in, sign out
- 9.1 Sessions
- 9.2 Signin failure
- 9.3 Signin success
- 9.4 Signing out
- 9.5 Conclusion
- 9.6 Exercises
- Chapter 10 Updating, showing, and deleting users
- 10.1 Updating users
- 10.2 Protecting pages
- 10.3 Showing users
- 10.4 Destroying users
- 10.5 Conclusion
- 10.6 Exercises
- Chapter 11 User microposts
- 11.1 A Micropost model
- 11.2 Showing microposts
- 11.3 Manipulating microposts
- 11.4 Conclusion
- 11.5 Exercises
- Chapter 12 Following users
- 12.1 The Relationship model
- 12.2 A web interface for following and followers
- 12.3 The status feed
- 12.4 Conclusion
- 12.5 Exercises
- Chapter 13 Rails 3.1
- 13.1 Upgrading the sample app
- 13.2 New features in Rails 3.1
- 13.3 Exercises
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.
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
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. * ------------------------------------------------------------ */
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).
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.
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.
$ 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
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
Gemfileneeded 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
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).
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.
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
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
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.
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.)
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.
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
In the case of code or images from external vendors, we use the
For the sample app, the above discussion means placing the
public/stylesheets/custom.css file in
app/assets/stylesheets/ and the logo image
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.
<![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' %>
<%= <type>_tag "application" %>
where the argument is the string
"application". In the case of CSS, the application file 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-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
to manipulate the
follow_form CSS id, jQuery writes
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
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
With these changes, and the changes to the asset locations from Section 126.96.36.199, 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.)
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.
Rails 3.1 also introduces reversible migrations, which allow Rails to infer the
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.
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
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.
.js files in
application.js file that is part of the Rails 3.1 asset pipeline.
- 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. ↑