The success of Rails has helped Ruby establish itself in web hosting stacks along with other script languages such as PHP, Perl, and Python. Although most Linux distributions offer a prebuilt Ruby package, developers and administrators might experience issues if the need arises to use multiple Ruby versions in parallel.
Additionally, choosing among the range of possible Ruby interpreters and versions becomes increasingly confusing. The classic Ruby interpreter – often referred to as "Matz's Ruby Interpreter," or MRI , after its main developer – is currently maintained in two branches, 1.8 and 1.9, because of changes that break its backward compatibility.
Projects that rely on Ruby 1.8 often use the Ruby Enterprise Edition (REE) , which adds an improved garbage collector, for live applications. Java-related and performance-critical projects use JRuby , a Ruby implementation in Java that leverages Java bindings in a Rails project.
RubyGems  is a de facto standard for extensions, comparable to Perl CPAN, PHP PEAR, and Python Eggs. Gems are managed via a separate package manager, which initially facilitates their use but can cause clutter in multiple projects with different Gem dependencies.
RVM  offers a solution for this complex interplay of Ruby interpreters, versions, and Gems, by helping developers maintain project-based environments.
The standard installation of RVM is a simple, although unusual, task for the administrator. As is often the case in the Ruby/Rails world, the installation script is executed directly on the network. You simply need to install Git and Curl up front. On Debian/Ubuntu you can prepare the system for the RVM installation by typing:
apt-get install curl git-core
If you follow the official "Quick Installation" method , you then call the script directly off the network in a command line:
bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
The Bash script, which will run on Linux and OS X, uses Git to download more program code off the web and then installs the latest version of RVM. Because it only rolls out shell-based wrapper scripts, there is no need to compile.
To use RVM interactively, the shell needs to know the path to RVM and to load a bootstrapper. If you have a user-specific installation, you need to add the following line at the end of your
~/.zshrc for Bash and Zsh, respectively:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"
After executing a new shell, or logging in again in some cases, the new
rvm command becomes available. A user-specific installation is recommended initially because it doesn't change any important files, doesn't need root privileges, and can easily be removed by typing
rm -rf ~/.rvm. On the other hand, if multiple users need to access RVM, there is no alternative to a global installation.
A global installation is launched in the same way as the user-specific installation but either with the use of
sudo or from the root account. The installation script detects its privileges for a global install and runs the installer accordingly. RVM is then dropped into
/usr/local/rvm, and then the
rvm command is added to
/usr/local/bin/rvm by means of a symlink. The bootstrapper for Bash and Zsh are deposited in
/etc/profile.d/rvm.sh, and an RVM group is created. Users who need to work with RVM must be members of this group; to do this, you can type
adduser USER rvm
The RVM installer logic has changed multiple times in the history of the project, so you might encounter some differences depending on the packages you use.
The next login with a user account applies the modified group privileges and accesses the bootstrapper, and the RVM command will be available. Login shells normally run the bootstrapper in
/etc/profile automatically, with no need for a manual extension, in contrast to the user-specific installation.
rvm help and
man rvm give you an overview of general use. Depending on the Ruby installation you are aiming for, you might need to fulfill a couple of dependencies.
rvm requirements shows you a distribution-dependent list of required dependencies for each Ruby version and how to resolve them with the package manager (see Table 1 for important RVM commands). The
apt-get calls for preparing the classic Ruby and the more exotic JRuby installations are shown in Figure 1.
Tabelle 1: Most Important RVM Commands
Show required dependencies
Show installed interpreters
Install an interpreter
Show the current RVM environment
Change the environment
Remove an interpreter
Show the release notes
Installing Ruby interpreters is easy once you have fulfilled the dependencies. This command:
rvm install ruby-1.9.2
installs version 1.9.2 of the classic Ruby interpreter with the current stable patch level. The installer downloads the sources and builds them on the target system. RVM warns you if a package is missing and outputs the commands you need to retrieve the package for your operating system or Linux distribution.
To pass in the configuration parameters for the configure script directly, use:
rvm install 1.9.2 --without-readline
JRuby and other Ruby interpreters are installed in the same way (e.g., with
ree-1.8.7). If you need a list of the Ruby derivatives and versions that RVM lets you install, just type
rvm list known. You will notice that you can specify a patch level (as in
ruby-1.8.7-p352), the current version (
-head), or a specific release status (e.g.,
-rc1), and for the classic Ruby interpreter, you can omit the name:
rvm install 1.9.2 will do the trick.
After completing the installation, type
rvm use to change to the Ruby environment.
rvm use 1.9.2 changes to the version installed in the example here. The version provided by the system can be re-enabled at any time by typing
rvm use system. The change to a specific RVM version is always session-specific. In other words, you can easily run two totally different Ruby versions in two terminal windows.
rvm info command gives you the details of the version you are currently using. Figure 2 shows the output after changing to the installed version 1.9.2. You can also clearly see how RVM works: Modifying the
PATH and other environmental variables makes it possible to change to a different environment without having to modify the filesystem.
RVM's handling of RubyGems is really useful. Although you might be able to run multiple Ruby versions in parallel with some reasonable overhead, the need to manage different "Gemsets" is definitely too much trouble.
A Gemset is simply a collection of Gems. RubyGems itself supports parallel operations with multiple versions of the same Gems. Rails, which is not a Gem itself, can theoretically be installed in multiple versions, each with its own set of dependencies. The Ruby code can then load the specific Gems. Unfortunately, many programs misbehave and will always load the latest version of a Gem, instead of a specific version, and this can lead to compatibility issues.
A useful approach in this case is to maintain Gems in a project-specific way instead of installing them arbitrarily; this guarantees the use of the required Gems. RVM uses Gemset containers for specific Gem collections. The following command
rvm gemset create project1
creates a Gemset by the name of
project1 in the current environment. You can then type:
rvm use 1.9.2@project1
to change to the Gemset. Any Gems installed with
gem install are only rolled out in the Gemsets for that version of Ruby. A faster approach is to type:
rvm use 1.9.2@projekt2 --create
which creates a Gemset and changes to it at the same time. If you need direct access to the Gem directory, you can type
rvm info or
echo $GEM_HOME to display the path.
Gemsets don't just give programmers a simple approach to isolating projects, they also let you test new Gem versions without risk. To copy the complete Gemset, enter:
rvm gemset copy 1.9.2@project1 1.9.2@project2
You can even do this between different Ruby versions. Similarly, you can save Gemsets in a
.gems file or import them from an existing file, by typing:
rvm gemset export/import
If you always need the same Gems for your new Gemsets, you can maintain a list of standard Gems in
~/.rvm/gemsets/global.gems. The Gems are automatically rolled out when you create a new Gemset (Listing 1).
Listing 1: ~/.rvm/gemsets/global.gems
LISTING Default Gemset bundler -v~>1.0.0 awesome_print shoutbox_client
RVM is configured in
/etc/rvmrc. The configuration is optional, but it does let you set specific compiler flags and paths. For a list of options, check out the
~/.rvm/examples/rvmrc file. The use of project-specific
.rvmrc configurations is more interesting. The RVM bootstrapper for Bash and Zsh, which I referred to earlier, loads RVM and also checks for a
.rvmrc file in the current directory when you change directory. If the file exists, it checks it once and then offers to load it automatically in future.
When you create a Gemset, you can automatically create a matching
.rvmrc file in the current folder:
rvm --rvmrc --create 1.9.2@project3
The first time you change to the directory, you need to confirm that you trust the file. After doing so, changing to the directory automatically changes to the corresponding Ruby version and Gemset. Thus, editing
.rvmrc gives developers a simple approach to publishing a shared Ruby version and named Gemset for multiple developers. New developers automatically receive the right version. The only drawback is that, although the Gemsets are created automatically, a missing Ruby version is not, so the developer will need to change this by typing
At the end of the day,
.rvmrc is simply a Bash script. A quick look at the automatically generated file shows that it relies on environmental variables and shell logic. In other words, it is a good idea to set other environmental variables in the
.rvmrc file or to modify RVM bootstrapping for the project in question (e.g., to stipulate the use of the 32-bit or 64-bit version of a Ruby interpreter).
Integration and Scripting
If you use services that build on Ruby and RubyGems, such as Passenger, the use of RVM can be tricky . Depending on the software you use, you need to check how you can integrate RVM. Often it is useful to define the absolute pathnames to the Ruby interpreters. RVM creates symbolic links for each Ruby version, and the symlinks can be executed directly.
To see the path details, enter
rvm info. Even if paths like
/home/ccm/.rvm/rubies/ruby-1.9.2-p290/bin/ruby look unusual, they point to a complete Ruby installation. The load process for Gemsets is managed by environmental variables, start scripts, or other bootstrappers, depending on the service. In the case of Passenger and Rails3, for example, you can set the paths in a
config/setup_load_paths.rb file in your Rails project.
For daily use of RVM, you have other useful helper scripts. For example, if you want to run a
sudo command while keeping the current RVM environment, you can use
rvmsudo as a wrapper. For use in shell scripts,
rvm-shell is an RVM Bash wrapper that lets you reference
.rvmrc files in non-interactive sessions. For cronjobs, you would probably want to set the
SHELL variable to the corresponding
rvm-shell to make sure scripts are executed correctly.
Advanced Ruby users and developers will find a collection of best practices and problem-specific solutions on the RVM website  . A discussion on interacting with the Gem bundler is under discussion, as is integration into developer environments, use in continuous integration systems like Hudson, and auto-completion in Zsh/Bash.
Ubuntu Oneiric Ocelot (11.10) is one of the first Linux distributions to include a package for RVM . It remains to be seen whether the atypical use of RVM in the distribution will harmonize with the package manager. Although supplying RVM as a package removes the first barrier, in the form of the non-standard install, it could come at the price of longer waits for what are normally very short RVM development cycles.
In automated server landscapes, RVM can be rolled out and managed conveniently with Puppet. Puppet modules are available from Github . If you are not afraid of experimenting, RVM might be your stepping stone to using the Scripting Management Framework (SM) . This system, which is also known as BDSM, is a scripting framework for server automation, which is mainly maintained by the RVM developers. This approach opens up interesting synergies and new perspectives in the interaction between server management and application deployment.
RVM is a complex meta-package manager for Ruby interpreters and Gemsets. Implementation with Bash scripts and negligible dependencies on Curl and git-core offer a fairly lean, albeit complex, solution. Despite some difficulties in managing RVM, the tool is currently the most popular solution of its kind in the Ruby world. Whether you choose to install via your distribution's package manager or not, there is currently no simpler way of handling Ruby management.