Imagine you’d want, for some reason, use an older version of a particular gem, rather than the latest one.
Maybe the authors of this gem have made a change that breaks your application. Of course they’d normally try to avoid this at all costs, but sometimes it still happens. (Another, maybe more common, case is that you are working on a Rails application that has been started a year ago, or is even older than that. Now a new major version of Rails comes out, and ships lots of changes that would break this application. So you want to stick to the older version of Rails until you get around making it ready for the newer one.)
One way to use an older version of a particular gem is to simply uninstall any newer versions from your system. E.g. you could run:
gem uninstall rails gem install rails --version '~> 3'
This would uninstall all rails gems, and then install the latest version of
Rails that still starts with a
3 (i.e. ignoring all the newer versions that,
as time of this writing, start with a
However, this is quite cumbersome. You’d need to figure out what versions of all the gems that you want to use are compatible with each other. And if you ever switch from one application to another you’d have to uninstall and reinstall all those gems over and over.
Instead, Bundler provides a much better way of picking certain gem versions out of the plethora of gems that might be installed on your computer.
In this example we are going to use the Chronic gem, which provides a great
way to convert natural language date formats to Ruby
Inside a new directory
chronic create a file
Gemfile, and add the following
source "https://rubygems.org" gem "chronic", "~> 0.9.0"
source directive says that we’d like to use the standard RubyGems.org
as a source for our gems. There are other sources, such as private Rubygems
servers run by companies to host their own, internal gems, or Rubygems servers
that people run in order to sell paid versions of their gems.
gem directive declares that we’d like to use the gem
we’d like to use any version that starts with
0.9 (for whatever reason).
Now, make sure you have
cded to that directory, and run:
You’ll see that Bundler first fetches some meta data from RubyGems.org. This means it checks what versions of the Chronic gem are available, what dependencies it has, and what dependencies these might have.
In our case Chronic doesn’t have any other dependencies, and so Bundler just
installs it. You will see that it installs a version starting with
time of this writing that would be
In order to check what gems are part of your bundle you can run
You can also open the file
Gemfile.lock that Bundler has created.
With this we’ve created a little gems sandbox that makes, no matter what other gems are available on your system, just two gems available to our Ruby code: Chronic, and Bundler itself.
Lets have a look at the load path to confirm that:
bundle exec ruby -e 'puts $LOAD_PATH'
You’ll se a bunch of directories that belong to your Ruby installation, and make its standard library available. But you’ll also see two directories that end with something similar to this:
This means that any code that we run using our bundle (i.e. standing in this
directory, and using
bundle exec as a prefix) will be able to require, and
use the Chronic library.
Let’s try that. Create a new file
19-bundler.rb in this directory, and add the
require "chronic" time = Chronic.parse('tomorrow') p time.class p time
This will output something like this:
Time 2015-05-15 12:00:00 +0200
You can see that the method
parse takes a natural language string, and converts
it into an instance of the Ruby class
Time (see here for the
documentation), so we can
now use this object’s methods to do more interesting stuff. E.g. let’s look up
which month that is:
require "chronic" time = Chronic.parse('tomorrow') puts time.month
Let’s say for some reason we’d now want to upgrade the Chronic gem, and use the
latest version in the newer
0.10 series. Maybe the authors have added some
new functionality that we’d like to use, or they’ve fixed a certain bug.
In order to do this we need to allow Bundler using the
0.10 series of versions.
So in your Gemfile change
~> 0.9.0 to
If you now run:
bundle update chronic
You’ll see that it now installs a newer version of this gem. Also, it has changed
the version number in the
Bundler is a really cool piece of software. It is one of those things that, once you’ve used it for a while, wonder how life was possible before it existed (“How on earth did people meet before there were cellphones?!?”). If you ask any seasoned Ruby developer how their life was before Bundler, they’ll probably respond “Quite miserable”, or maybe give you a blank stare and say “Ummm, I forgot”.