Getting Ready for Rails 6.0: How to Dual Boot

RailsConf 2019 is right around the corner. That means Rails 6.0 is right around the corner! Rails 6.0's beta has been available since January 18, 2019. Rails 6.0.0.rc1 was released today! 🎉

In this article I will explain how you can dual boot your application in your local environment and your CI server. I hope that this will help you get ready for the next stable release of Rails.

Even though my example assumes you are running Rails 5.2 and want to migrate to Rails 6.0, these tips work for any two versions of Rails.

Create a Gemfile.next File

At RailsConf 2018, Jordan Raine talked about Clio's process to upgrade Rails over the years. If you missed his talk, you can watch it over here: Ten Years of Rails Upgrades

In his talk he mentioned quite a handy companion gem: ten_years_rails. I'm going to use that gem to get my project ready for dual booting. First, I need to install it in my local environment.

$ gem install ten_years_rails
Successfully installed ten_years_rails-0.2.0
Parsing documentation for ten_years_rails-0.2.0
Installing ri documentation for ten_years_rails-0.2.0
Done installing documentation for ten_years_rails after 0 seconds
1 gem installed

Warning: ten_years_rails requires Ruby 2.3 or higher. You can find a manual workaround below.

Now that I can use that gem, I will initialize my Gemfile.next file like this:

$ next --init
Created Gemfile.next (a symlink to your Gemfile). Your Gemfile has been modified
to support dual-booting!

There's just one more step: modify your Gemfile to use a newer version of Rails
using the `next?` helper method.

For example, here's how to go from 5.2.3 to 6.0:

if next?
  gem "rails", "6.0.0"
else
  gem "rails", "5.2.3"
end

That command creates a Gemfile.next symlink to my Gemfile and adds an util method to my Gemfile:

# Gemfile
def next?
  File.basename(__FILE__) == "Gemfile.next"
end

source 'https://rubygems.org'
# ...

If you have any problems installing ten_years_rails, you can manually add the next? method to your Gemfile and create a symlink like this:

$ cd path/to/project
$ ln -s Gemfile Gemfile.next

Bump Rails (Gemfile.next)

In this simple example, I only need to upgrade rails (from Rails 5.2 to Rails 6.0). It's very likely that you will have to upgrade more dependencies. My Gemfile now looks like this:

def next?
  File.basename(__FILE__) == "Gemfile.next"
end

source 'https://rubygems.org'

if next?
  gem 'rails', '~> 6.0.0'
else
  gem 'rails', '~> 5.2.3'
end

# ...

Now I can install my current dependencies with bundle install and my future dependencies with next bundle install. If next bundle install doesn't work for you, you can just run BUNDLE_GEMFILE=Gemfile.next bundle install. As a general rule, if next <command> doesn't work in your environment you can replace it with BUNDLE_GEMFILE=Gemfile.next <command>.

Run Tests

After running next bundle install, I have a brand new Gemfile.next.lock file. That means that my dependencies are ready to run my test. So I can run them like this:

$ next bundle exec rake

The main advantage of using dual booting your Rails application is that you can run your tests with two different versions of Rails. Running bundle exec rake still works thanks to the conditionals in your Gemfile.

Setup Continuous Integration

Depending on the type of project, we like to use Travis CI or Circle CI. So below you will find a couple of sample configuration files that you could use.

Both samples will require you to commit and push Gemfile.next to your repository; will run a build matrix; and might need some tweaking.

Circle CI

For all of our client projects we prefer this continuous integration service. Here is the configuration that you could use for dual booting in Circle CI:

A few notes about this configuration:

  • It's using Ruby 2.6 and a Postgres database
  • It's using Circle CI's API version 2.0
  • It has a lot of duplication (there is probably a way to DRY it)
  • The key is to configure a workflow with two jobs (one for Rails 5.2 and another one for Rails 6.0) like this:
workflows:
  version: 2
  build:
    jobs:
      - "build-rails-5-2"
      - "build-rails-6-0"

Travis CI

For all of our open source projects we prefer this continuous integration service. Here is the configuration that you could use for dual booting in Travis CI:

A few notes about this configuration:

  • It's for an open source application that is using Postgres
  • You might not need some of the things in this sample
  • It's certainly simpler than the Circle CI configuration. I love how simple it is to configure a build matrix in Travis CI:
rvm:
- 2.2.6
gemfile:
- Gemfile
- Gemfile.next

Start Fixing The Rails 6.0 Test Suite

Now that you have your test suite running in both Rails 5.2 and Rails 6.0, you can start tweaking your code and dependencies to work with both gemfiles. There will be two big hurdles:

  1. Getting Bundler to bundle your dependencies
  2. Getting your test suite to pass

Final Remarks

This has been quite a useful technique for us at fastruby.io. We have used it with client projects, internal projects, and open source applications.

I hope that you will find it useful in getting ready for the upcoming Rails 6.0 stable release.