#282 Upgrading to Rails 3.1
Rails 3.1 has finally been released. There’s a great overview of its new features in the Release Notes on the RailsGuides site some of which have been covered on the Railscasts site and also here. In this episode we’ll focus on upgrading a Rails 3.0 application to 3.1 and we’ll use the Railscasts site as our example.
Preparing The Site
Before we upgrade the site to Rails 3.1 we’ll need to take a few preparatory steps. If the site isn’t currently running the latest version of Rails 3.0, currently
3.0.10, we’ll need to update it. We can do this by setting the version in the Gemfile and then running
gem "rails", "3.0.10"
Next we’ll run the application’s test suite to make sure that all of the tests still pass and that there are no deprecation errors. If there are then we’ll need to fix these before we continue. Everything passes in the Railscasts code so we can proceed with the upgrade.
We’re ready to start to upgrade the site now. We’ll do this inside a new Git branch that we’ll call
$ git checkout -b rails31
Upgrading to Rails 3.1 is pretty simple. We just need to go to our application’s
Gemfile again and change the version number to whatever the latest release of 3.1 is, currently
gem "rails", "3.1.0"
Now we can run
bundle update to install the new version. The only other change we need to make is to the
development.rb configuration file where we need to remove or comment out the following line.
# config.action_view.debug_rjs = true
If we run our tests again now we’ll see that they all still pass. We can even start up the Rails server and see it running in the browser.
Modifying Our Application To Use The Asset Pipeline
/public directory we’re not taking advantage of it at all. The asset pipeline is completely optional and doesn’t come into effect unless we enable it so if we’re not sure about using it this doesn’t stop us from upgrading to Rails 3.1. Given how easy it is to upgrade this means that there’s very little reason not to.
If we do want to use the asset pipeline we have to enable it. To do this we have to add the following lines to the
Gemfile. (These come from the
Gemfile that is generated when we create a new Rails 3.1 application.)
# Gems used only for assets and not required # in production environments by default. group :assets do gem 'sass-rails', " ~> 3.1.0" gem 'coffee-rails', " ~> 3.1.0" gem 'uglifier' end gem 'jquery-rails'
This code creates an
assets group and puts some asset-related gems in it. It also includes the
jquery-rails gem so that we can use jQuery. (If you prefer to use Prototype there’s a
prototype-rails gem you can use instead.) We’ll also need to modify
/config/application.rb, replacing this code:
# If you have a Gemfile, require the gems listed there, including any gems # you've limited to :test, :development, or :production. Bundler.require(:default, Rails.env) if defined?(Bundler)
if defined?(Bundler) # If you precompile assets before deploying to production, use this line Bundler.require *Rails.groups(:assets => %w(development test)) # If you want your assets lazily compiled in production, use this line # Bundler.require(:default, :assets, Rails.env) end
This code adds the
assets group to the groups that are required by
Bundler. We’ll need to enable the asset pipeline in this file, too, which we can do by adding these lines of code inside the
# Enable the asset pipeline config.assets.enabled = true # Version of your assets, change this if you want to expire all your assets config.assets.version = '1.0'
This code enables the asset pipeline and also gives it a version number. This number can be changed when we want to expire the assets.
We also need to change the configuration settings in each environment’s configuration file. We’ll start with
development.rb. We need to make a couple of changes here so that the assets aren’t compressed and to enable asset debugging.
# Do not compress assets config.assets.compress = false # Expands the lines which load the assets config.assets.debug = true
Next we’ll modify
In production mode we want to compress the assets, but we set
false so that it doesn’t fallback on to the asset pipeline if we’re going to precompile them. We also set
true so that the assets’ URLs are fingerprinted. We can, of course, configure these options differently to suit how our applications work in production mode.
Lastly we’ll modify the test environment. Here we add options so that static assets are served and cached and we also enable asset debugging.
# Configure static asset server for tests with Cache-Control for performance config.serve_static_assets = true config.static_cache_control = "public, max-age=3600" # Allow pass debug_assets=true as a query parameter to load pages with unpackaged assets config.assets.allow_debugging = true
If we’re using Git for our application’s source control we should also modify the
.gitignore file and add the
.sass-cache directory to the list of ignored items. We don’t want the SASS cache in Git.
Moving The Assets
Now that our asset pipeline is configured it’s time to create the
/app/assets directory. We can then move the
stylesheets directories from
Some of the files we’ve moved aren’t needed anymore, such as the jQuery-related files in the
rails.js. Now is also a good time to decide if we want to move some files such as jQuery plugins into
/vendor/assets, like we did in episode 279 [watch, read].
Next we’ll need to create the manifest files. This application already has
application.css files in the relevant directories so we don’t need to create them. We’ll start with the CSS file. To turn it in into a manifest file we need to add some comments at the top that will tell Sprockets which files to include. (The Sprockets syntax was also covered back in episode 279). We’ll tell Sprockets to include the rest of the file itself and also all of the other files inside the stylesheets directory and its subdirectories.
/* *= require_self *= require_tree . */ /* rest of file omitted */
We can do the same to the
application.js file, but we’ll need to do something a little different here as we want to include jQuery.
//= require jquery //= require jquery_ujs //= require_self //= require_tree . /* rest of file omitted */
Again we add
require_self here as the file itself contains code and also
require_tree so that and other files under the same directory are included.
Now’s the time to try our application in the browser to make sure that our changes have all worked. Before we do we’ll run
bundle again to install all of the gems that we added. After they’ve installed we can start up the server.
$ rails s
Everything mostly works but there are some broken images, for example the logo at the top of the screen.
The problem with this is that the image’s URL has been hard-coded in the layout file.
<img src="/images/railscasts_logo.png" width="423" height="56" alt="RailsCasts = Ruby on Rails Screencasts"/>
This won’t work as our application’s images are no longer in the
/public/images directory. The simplest solution might appear to be to change the image’s URL from
/assets/railscasts_logo.png and while this will appear to work in development mode we’ll run into issues in production. If we have the
assets.digest option enabled this will add a hash at the end of the name and so a static reference to that file will no longer work. We should instead always use the helper methods. This will link the image correctly in both development and production mode.
<%= image_tag("railscasts_logo.png", :size => "423x56", :alt => "RailsCasts - Ruby on Rails Screencasts") %>
We’ll need to globally search through our application and change any statically-referenced assets so that they use the helper methods like the image above. If we reload the page now the image appears which means that our asset pipeline is now working correctly.
We’ve pretty much finished upgrading our application to Rails 3.1. There are some other new features you can take advantage of and it’s worth taking a look at the other episodes on Rails 3.1 to see if they would be useful in your applications.