Getting Ready for Rails 6.0: How to Dual Boot
In this article I will explain how you can dual boot your application in your local environment and your continuous integration (CI) service. 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 . At FastRuby.io we decided to fork
it and call it
next_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 next_rails Successfully installed next_rails-1.0.2 Parsing documentation for next_rails-1.0.2 Installing ri documentation for next_rails-1.0.2 Done installing documentation for next_rails after 0 seconds 1 gem installed
next_rails requires Ruby 2.3 or higher. You can find a manual
Assuming 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 and adds a handy method called
next? to my
Why to use a symlink
I see three main benefits to using a symlink:
The way Bundler works it will generate one
.lockfile per Gemfile. If you manage all your dependencies logic in your Gemfile (without
Gemfile.next) and your
Gemfile.lockis checked in to your Git repository, then you will have to constantly resolve conflicts between your long running upgrade branch and
master. This will become tedious if you have a really active
masterbranch and your upgrade project lasts months (not weeks)
By making it a symlink to
Gemfile, you can keep all your logic inside one file. That means that you can quickly see what are the main difference between your current version of Rails and the next version.
You can use Bundler’s
BUNDLE_GEMFILEenvironment variable. Because a symlink is transparent to Bundler, it assumes that you have two physical files. You can later switch between one version of Rails or the other by just adding one environment variable to your command line.
# Gemfile def next? File.basename(__FILE__) == "Gemfile.next" end source 'https://rubygems.org' # ...
If you have any problems installing
next_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. The
first step is to get my
Gemfile to look 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
next bundle update. If
next bundle update 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
next bundle <command> might not work because you are using an old version of
Bundler . So, you should try using Bundler 2.0 or higher.
next bundle update, I have a brand new
That means that my dependencies are ready to run my test suite. So I can run
them like this:
$ next bundle exec rake
There are many advantages to using dual booting in your Rails application. In no particular order:
- You can run your test suite with two different versions of Rails. Running
bundle exec rakestill works thanks to the conditionals in your
- You can run your application in development with two different versions of
Rails. Simply prepend
bundle exec rails server.
- You can even run your application in staging using the next version of Rails.
Simply make sure that you set this environment variable:
- You can quickly debug issues between your current version of Rails and the
next one. Dual booting plus
debuggeris a powerful combo for finding bugs between versions.
Setup Continuous Integration
Depending on the type of project, we like to use Travis CI for open source projects and Circle CI for client projects. 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.
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"
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:
- Getting Bundler to bundle your dependencies
- Getting your test suite to pass
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 next version of Rails!