Ruby on Rails Tutorial

Learn Rails by Example

Michael Hartl

Contents

  1. Chapter 1 From zero to deploy
    1. 1.1 Introduction
      1. 1.1.1 Comments for various readers
      2. 1.1.2 “Scaling” Rails
      3. 1.1.3 Conventions in this book
    2. 1.2 Up and running
      1. 1.2.1 Development environments
        1. IDEs
        2. Text editors and command lines
        3. Browsers
        4. A note about tools
      2. 1.2.2 Ruby, RubyGems, Rails, and Git
        1. Rails Installer (Windows)
        2. Install Git
        3. Install Ruby
        4. Install RubyGems
        5. Install Rails
      3. 1.2.3 The first application
      4. 1.2.4 Bundler
      5. 1.2.5 rails server
      6. 1.2.6 Model-view-controller (MVC)
    3. 1.3 Version control with Git
      1. 1.3.1 Installation and setup
        1. First-time system setup
        2. First-time repository setup
      2. 1.3.2 Adding and committing
      3. 1.3.3 What good does Git do you?
      4. 1.3.4 GitHub
      5. 1.3.5 Branch, edit, commit, merge
        1. Branch
        2. Edit
        3. Commit
        4. Merge
        5. Push
    4. 1.4 Deploying
      1. 1.4.1 Heroku setup
      2. 1.4.2 Heroku deployment, step one
      3. 1.4.3 Heroku deployment, step two
      4. 1.4.4 Heroku commands
    5. 1.5 Conclusion
  2. Chapter 2 A demo app
    1. 2.1 Planning the application
      1. 2.1.1 Modeling users
      2. 2.1.2 Modeling microposts
    2. 2.2 The Users resource
      1. 2.2.1 A user tour
      2. 2.2.2 MVC in action
      3. 2.2.3 Weaknesses of this Users resource
    3. 2.3 The Microposts resource
      1. 2.3.1 A micropost microtour
      2. 2.3.2 Putting the micro in microposts
      3. 2.3.3 A user has_many microposts
      4. 2.3.4 Inheritance hierarchies
      5. 2.3.5 Deploying the demo app
    4. 2.4 Conclusion
  3. Chapter 3 Mostly static pages
    1. 3.1 Static pages
      1. 3.1.1 Truly static pages
      2. 3.1.2 Static pages with Rails
    2. 3.2 Our first tests
      1. 3.2.1 Testing tools
        1. Autotest
      2. 3.2.2 TDD: Red, Green, Refactor
        1. Spork
        2. Red
        3. Green
        4. Refactor
    3. 3.3 Slightly dynamic pages
      1. 3.3.1 Testing a title change
      2. 3.3.2 Passing title tests
      3. 3.3.3 Instance variables and Embedded Ruby
      4. 3.3.4 Eliminating duplication with layouts
    4. 3.4 Conclusion
    5. 3.5 Exercises
  4. Chapter 4 Rails-flavored Ruby
    1. 4.1 Motivation
      1. 4.1.1 A title helper
      2. 4.1.2 Cascading Style Sheets
    2. 4.2 Strings and methods
      1. 4.2.1 Comments
      2. 4.2.2 Strings
        1. Printing
        2. Single-quoted strings
      3. 4.2.3 Objects and message passing
      4. 4.2.4 Method definitions
      5. 4.2.5 Back to the title helper
    3. 4.3 Other data structures
      1. 4.3.1 Arrays and ranges
      2. 4.3.2 Blocks
      3. 4.3.3 Hashes and symbols
      4. 4.3.4 CSS revisited
    4. 4.4 Ruby classes
      1. 4.4.1 Constructors
      2. 4.4.2 Class inheritance
      3. 4.4.3 Modifying built-in classes
      4. 4.4.4 A controller class
      5. 4.4.5 A user class
    5. 4.5 Exercises
  5. Chapter 5 Filling in the layout
    1. 5.1 Adding some structure
      1. 5.1.1 Site navigation
      2. 5.1.2 Custom CSS
      3. 5.1.3 Partials
    2. 5.2 Layout links
      1. 5.2.1 Integration tests
      2. 5.2.2 Rails routes
      3. 5.2.3 Named routes
    3. 5.3 User signup: A first step
      1. 5.3.1 Users controller
      2. 5.3.2 Signup URL
    4. 5.4 Conclusion
    5. 5.5 Exercises
  6. Chapter 6 Modeling and viewing users, part I
    1. 6.1 User model
      1. 6.1.1 Database migrations
      2. 6.1.2 The model file
        1. Model annotation
        2. Accessible attributes
      3. 6.1.3 Creating user objects
      4. 6.1.4 Finding user objects
      5. 6.1.5 Updating user objects
    2. 6.2 User validations
      1. 6.2.1 Validating presence
      2. 6.2.2 Length validation
      3. 6.2.3 Format validation
      4. 6.2.4 Uniqueness validation
        1. The uniqueness caveat
    3. 6.3 Viewing users
      1. 6.3.1 Debug and Rails environments
      2. 6.3.2 User model, view, controller
      3. 6.3.3 A Users resource
        1. params in debug
    4. 6.4 Conclusion
    5. 6.5 Exercises
  7. Chapter 7 Modeling and viewing users, part II
    1. 7.1 Insecure passwords
      1. 7.1.1 Password validations
      2. 7.1.2 A password migration
      3. 7.1.3 An Active Record callback
    2. 7.2 Secure passwords
      1. 7.2.1 A secure password test
      2. 7.2.2 Some secure password theory
      3. 7.2.3 Implementing has_password?
      4. 7.2.4 An authenticate method
    3. 7.3 Better user views
      1. 7.3.1 Testing the user show page (with factories)
      2. 7.3.2 A name and a Gravatar
        1. A Gravatar helper
      3. 7.3.3 A user sidebar
    4. 7.4 Conclusion
      1. 7.4.1 Git commit
      2. 7.4.2 Heroku deploy
    5. 7.5 Exercises
  8. Chapter 8 Sign up
    1. 8.1 Signup form
      1. 8.1.1 Using form_for
      2. 8.1.2 The form HTML
    2. 8.2 Signup failure
      1. 8.2.1 Testing failure
      2. 8.2.2 A working form
      3. 8.2.3 Signup error messages
      4. 8.2.4 Filtering parameter logging
    3. 8.3 Signup success
      1. 8.3.1 Testing success
      2. 8.3.2 The finished signup form
      3. 8.3.3 The flash
      4. 8.3.4 The first signup
    4. 8.4 RSpec integration tests
      1. 8.4.1 Integration tests with style
      2. 8.4.2 Users signup failure should not make a new user
      3. 8.4.3 Users signup success should make a new user
    5. 8.5 Conclusion
    6. 8.6 Exercises
  9. Chapter 9 Sign in, sign out
    1. 9.1 Sessions
      1. 9.1.1 Sessions controller
      2. 9.1.2 Signin form
    2. 9.2 Signin failure
      1. 9.2.1 Reviewing form submission
      2. 9.2.2 Failed signin (test and code)
    3. 9.3 Signin success
      1. 9.3.1 The completed create action
      2. 9.3.2 Remember me
      3. 9.3.3 Current user
    4. 9.4 Signing out
      1. 9.4.1 Destroying sessions
      2. 9.4.2 Signin upon signup
      3. 9.4.3 Changing the layout links
      4. 9.4.4 Signin/out integration tests
    5. 9.5 Conclusion
    6. 9.6 Exercises
  10. Chapter 10 Updating, showing, and deleting users
    1. 10.1 Updating users
      1. 10.1.1 Edit form
      2. 10.1.2 Enabling edits
    2. 10.2 Protecting pages
      1. 10.2.1 Requiring signed-in users
      2. 10.2.2 Requiring the right user
      3. 10.2.3 Friendly forwarding
    3. 10.3 Showing users
      1. 10.3.1 User index
      2. 10.3.2 Sample users
      3. 10.3.3 Pagination
        1. Testing pagination
      4. 10.3.4 Partial refactoring
    4. 10.4 Destroying users
      1. 10.4.1 Administrative users
        1. Revisiting attr_accessible
      2. 10.4.2 The destroy action
    5. 10.5 Conclusion
    6. 10.6 Exercises
  11. Chapter 11 User microposts
    1. 11.1 A Micropost model
      1. 11.1.1 The basic model
        1. Accessible attribute
      2. 11.1.2 User/Micropost associations
      3. 11.1.3 Micropost refinements
        1. Default scope
        2. Dependent: destroy
      4. 11.1.4 Micropost validations
    2. 11.2 Showing microposts
      1. 11.2.1 Augmenting the user show page
      2. 11.2.2 Sample microposts
    3. 11.3 Manipulating microposts
      1. 11.3.1 Access control
      2. 11.3.2 Creating microposts
      3. 11.3.3 A proto-feed
      4. 11.3.4 Destroying microposts
      5. 11.3.5 Testing the new home page
    4. 11.4 Conclusion
    5. 11.5 Exercises
  12. Chapter 12 Following users
    1. 12.1 The Relationship model
      1. 12.1.1 A problem with the data model (and a solution)
      2. 12.1.2 User/relationship associations
      3. 12.1.3 Validations
      4. 12.1.4 Following
      5. 12.1.5 Followers
    2. 12.2 A web interface for following and followers
      1. 12.2.1 Sample following data
      2. 12.2.2 Stats and a follow form
      3. 12.2.3 Following and followers pages
      4. 12.2.4 A working follow button the standard way
      5. 12.2.5 A working follow button with Ajax
    3. 12.3 The status feed
      1. 12.3.1 Motivation and strategy
      2. 12.3.2 A first feed implementation
      3. 12.3.3 Scopes, subselects, and a lambda
      4. 12.3.4 The new status feed
    4. 12.4 Conclusion
      1. 12.4.1 Extensions to the sample application
        1. Replies
        2. Messaging
        3. Follower notifications
        4. Password reminders
        5. Signup confirmation
        6. RSS feed
        7. REST API
        8. Search
      2. 12.4.2 Guide to further resources
    5. 12.5 Exercises
  13. Chapter 13 Rails 3.1
    1. 13.1 Upgrading the sample app
      1. 13.1.1 Installing and configuring Rails 3.1
      2. 13.1.2 Getting to Red
      3. 13.1.3 Minor issues
        1. will_paginate
        2. Pagination spec
      4. 13.1.4 Major differences
        1. Asset directories
        2. Prototype to jQuery
    2. 13.2 New features in Rails 3.1
      1. 13.2.1 Asset pipeline
      2. 13.2.2 Reversible migrations
      3. 13.2.3 Sass and CoffeeScript
    3. 13.3 Exercises

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.)

Listing 13.1. The sample application 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.

upgrade_with_finder
Figure 13.1: Upgrading the sample app by copying files one by one. (full size)

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

Listing 13.2. The change needed in the will_paginate gem.
  # 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.

Listing 13.3. The diff for the pagination test.
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.

Listing 13.4. The diff for the layout file 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">
Listing 13.5. The diff for the stylesheets partial 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.

Listing 13.6. The Prototype-to-jQuery diff for 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" %>')
Listing 13.7. The Prototype-to-jQuery diff for 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" %>')
Listing 13.8. The jQuery code needed to create a following relationship.
app/views/relationships/create.js.erb
$("#follow_form").html("<%= escape_javascript(render('users/unfollow')) %>")
$("#followers").html('<%= "#{@user.followers.count} followers" %>')
Listing 13.9. The jQuery code needed to destroy a following relationship.
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.

Listing 13.10. Migration for the User model (to create a 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
Listing 13.11. A reversible (Rails 3.1–style) migration for the User model.
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

  1. 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.
  2. (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.)
  1. 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. 
Michael Hartl is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to Amazon.com.