Recently, we upgraded all neeto product's Ruby version from 3.2.2 to 3.3.0 using "dual-booting".
Dual-booting is a process that allows you to run your application with different sets of dependencies, making it easy to switch between them. This approach enables you to quickly test your code with both the current and the newer version of what you are upgrading, ensuring that everything works smoothly before fully committing to the upgrade.
The dual-boot technique involves maintaining two separate Gemfile.lock
files
within your Rails project: one for the current version of Ruby and another for
the next version you're upgrading to.
To get started, first create a symbolic link for Gemfile.next
with the
following command:
ln -s Gemfile Gemfile.next
This command creates Gemfile.next
file, which you'll use for the new Ruby
version. This file isn't a separate copy but rather a pointer to your original
Gemfile
in the Rails project directory.
Next, add the following snippet at the top of your Gemfile
:
def next?
File.basename(__FILE__) == "Gemfile.next"
end
This code snippet helps determine which Gemfile
is in use, whether it's the
standard one or the Gemfile.next
for the new Ruby version.
Now, let's utilize the next?
method to dynamically set the Ruby version in the
Gemfile
using a conditional operator:
ruby_version = next? ? "3.3.0" : "3.2.2"
ruby ruby_version
This code snippet helps determine the Ruby version based on the next?
method.
If next?
returns true, meaning you're operating within Gemfile.next
, it sets
the Ruby version to "3.3.0". Otherwise, if the standard Gemfile
is being
processed, it defaults to "3.2.2".
With the dual-boot setup in place, you can effectively manage dependencies for both your current and next versions of the application.
Installing current dependencies: To install dependencies for your current version, simply run:
bundle install
This command uses the standard Gemfile
to resolve and install dependencies for
your current application.
Installing next dependencies: To install dependencies for the next version of your application, use the following command:
BUNDLE_GEMFILE=Gemfile.next bundle install
This command specifies Gemfile.next
as the Gemfile
, allowing you to install
dependencies specifically for the next version.
Managing commands for the next version: To perform various operations for the
next version, you can use the syntax BUNDLE_GEMFILE=Gemfile.next <command>
.
For example, to start the Rails server with the next version's dependencies, you
would use:
BUNDLE_GEMFILE=Gemfile.next rails s
This approach ensures that Gemfile.next
is explicitly used for the specified
command, allowing you to work with the next version of your application while
keeping dependencies and configurations correctly managed.
When implementing a dual-boot setup, it's crucial to consider where both Ruby
and gem versions are defined. While gem versions are usually specified only in
the Gemfile
, the Ruby version can be defined in several locations. The most
common are:
.ruby-version
File: Used by version managers like rbenv to specify the Ruby
version.Gemfile
: This is where Bundler, RVM, Heroku, and similar tools reference the
Ruby version to manage the Ruby environment.Gemfile.lock
: Although the Ruby version in this file is mostly informative,
it's worth noting.Dockerfile
: Defines the Ruby version for Docker containers if you're using
Docker.We need to make sure that dual-boot setup is compatible with all of them to ensure a smooth transition and consistency across different environments.
If this blog was helpful, check out our full blog archive.