I recently completed our upgrade to Rails 4. Below are various notes and links that may help you if you are upgrading your application to Rails 4. YMMV.
There is a good Rails Guide on upgrading, with a specific section on upgrading from Rails 3.2 to Rails 4.0. First, a bit about our specific application and the technologies used, pre-Rails 4 upgrade:
- Rails 3.2.14
- Ruby 2.0.0-p247
- Unicorn
- MongoDB w/ Mongoid
- Redis with Sidekiq for worker jobs
- Haml, Sass, Zurb Foundation, CoffeeScript, jQuery
- Devise, Devise Invitable, OmniAuth
- Stripe
- Mailchimp
- Capistrano
As noted in the Rails Guide on upgrading, you will probably want to make sure you have tests, that you are using Ruby 1.9.3 (although Ruby 2.0.0 is better) and that you are on Rails 3.2.x. The first step for me was deciding on a way to mark Rails 4 issues that I needed to address as I was doing the upgrade. I decided a comment of # RAILS4: would be straightforward and easily searchable in our project.
All of this work was done in a rails-4-upgrade
branch.
The next step for me was upgrading the rails gem requirement in our Gemfile
.
gem 'rails', '~> 4.0.0'
After that I ran bundle update rails
and it was all aboard the Failboat for a 3 hour tour. In reality, it wasn't that bad. The main issue with updating the rails gem were requirements from other gems on specific items such as activemodel. The gems in our application that required going against GitHub versions as of now are:
- plataformatec/simple_form
- mongoid/mongoid
- scambra/devise_invitable
- mongoid/kiqstand
The one gem in our application that I could use an alpha release gem was:
- compass-rails, '~> 2.0.alpha.0'
Once I was able to get bundle update rails
to successfully run and there were no issues running bundle install
, I ran guard and made adjustments to the application to address specific issues in the code and/or tests. Those items were as follows:
- Added the
protected_attributes
gem to continue to useattr_accessible
in a few of our models. - Added the
actionpack-page_caching
gem to be able to use thecaches_page
method. This is used in our application wherein we pre-cache our error pages to be able to use our application's stylesheets. - A few places in our application used Mongoid's
#set
method on models and this changed from being able to set a single attribute to being able to provide a Hash of attribute/value pairs. - Adding the appropriate
config.eager_load = false
orconfig.eager_load = true
to the various environment configuration files, e.g.config/environments/production.rb
. - Ensuring the match-style routes in our
routes.rb
file added the appropriate allowed HTTP methods, e.g.via: [:get]
. - As observers have been removed from Rails 4 and moved to a gem, Mongoid had removed observers as well. The 4 observers we had in our application were refactored to use callbacks on the model class. All the observers, and subsequently the callbacks, were doing was to put jobs into Sidekiq.
We have staging and shadowed environments for our application. The staging
environment goes against a separate backend and has limited access based on location and user while the shadowed
environment goes against the production backend, but has limited access based on location and user. I deployed the rails-4-upgrade
branch to our shadowed
environment. As we use capistrano for deploying our application, I came across a capistrano wiki page on capistrano, Rails 4 and the Asset pipeline. The gist of that being that I only had to remove the Rails 3.x manifest.yml
file.
Once I had successfully deployed and used the application in the shadowed
environment, I deployed the rails-4-upgrade
branch to production and let the application be used by everyone for an afternoon. Towards the end of the day I merged the Rails 4 upgrade pull request.
I only made 2 updates after our Rails 4 upgrade was deployed to production. Those fixes were as follows:
- Although the Rails upgrade guide mentions, "Rails 4.0 requires that scopes use a callable object such as a Proc or lambda", there was one model with a scope that did not use a lambda. However, the tests ran fine and the one part of the application that exercised that scope did not error out.
- We had a partial with a - in the name, not a _ and the application threw an error. I renamed that partial to use a _. However, the partial with the - in the name was allowed under Rails 3.2.x. The specific error I received was:
ActionView::Template::Error: The partial name (header-pro) is not a valid Ruby identifier;
make sure your partial name starts with a lowercase letter or underscore, and is followed
by any combination of letters, numbers and underscores.
So far so good. I should also note that all of this was done with zero downtime.
Happy Rails 4-ing! I'd be glad to address any comments and/or questions.
Thanks! Your tip on the partial naming helped.