Rails 3 revolutionizes gem dependency management by including a new library called Bundler. This new system supersedes the old
config.gem system that was built in to Rails 2. It provides all of the functionality of that system and a lot more — now you can be confident that the gems your application depends on will be the same on every developer’s machine as well as every application server.
This week, we’ve got a screencast showing how you would work with gems in Rails 3, and a post describing the most common features of the Bundler in more detail. Both should be suitable for those who have never used Bundler before, but we assume at least a passing knowledge of Rubygems.
In Rails 3, you list all of the gems that your application requires, along with any version requirements you might have in a
rails command creates a default
Gemfile for you when you generate a new empty Rails application. The default
Gemfile includes just two gems: Rails itself, and the default database driver, the
If your application requires other gems, you can edit the Gemfile to list them:
gem "nokogiri" gem "will_paginate", "3.0.pre"
As you can see, you can request specific versions of a given gem by adding the version number after the name.
Once you have set up your
Gemfile, run the command
bundle install to set up all of the gems in your bundle for use with your application. If any of the gems aren’t installed, Bundler will automatically download and install them.
When Rails loads, it will automatically require each of the gems listed in your Gemfile, using the same name as the gem. If the file Rails should require differs from the gem name (for example, sqlite3-ruby is required as “sqlite3”), you should specify the correct name in the Gemfile like this:
gem "sqlite3-ruby", :require => "sqlite3"
While you’re developing and testing your Rails application, you may find that there are some gems that you only want to load in certain environments. If there are gems that you only want to load while you are developing your application (like
rack-bug, perhaps), you can specify that in your
group :development do gem "ruby-debug" gem "rack-bug" end
You can specify gems that should only load in any of the Rails environments, which includes
:production in a default application. If you have a gem that should be in more than one group, you can either put it in each group block, or you can specify multiple groups on the gem line itself, like
gem "ruby-debug", :group => [:test, :development].
You can avoid installing certain groups of gems if they will not compile. For example, some Rails applications use PostgreSQL in production, and sometimes getting the
pg gem to compile can be hard. To exclude the
test groups, you would run
bundle install --without production test.
You can take a snapshot of the exact versions of every gem used by your application with the
bundle lock command. When you run
bundle lock, it will create a file named
Gemfile.lock in the root of your application. That file stores the snapshot, including the names and versions of every gem.
You should check this file in to your version control, so that everyone who checks the code out will have the exact same gems. When you run
bundle install on an application that has a snapshot, it will install the exact same versions of every gem (including all dependencies and dependencies’ depencencies) that the application was using when you ran
bundle lock. This is a good way to ensure that all development and production machines are running the exact same versions of every gem that your application uses.
Deploying to a server
When you are ready to deploy your Rails application to a server, commit both the
Gemfile.lock files to your source control. Then, as part of your deploy process, run
bundle install before you start your application servers. All of the gems your application depends on will be installed and configured, and your application will be running in production on the exact same gems and versions that you used in development. It’s that easy.
Advanced uses of Bundler
In order to develop and deploy your Rails application, you don’t need to know more than this article already covered. However, Bundler comes with several advanced features that can be very useful under specific circumstances. If you are interested in learning about some of the more advanced capabilities, they are described below.
Advanced: Git dependencies
While you should always use gems that have been released to Rubyforge if you can, sometimes there is a fix that you absolutely need that is only available in the gem’s git repository. In this case, you can use the :git option to specify a git repository as the source for a specific gem. Gems that come from git repositories participate in dependency resolution exactly like regular gems, and their dependencies will be installed if needed.
When you are using the
:git option, you can also specify a
:ref option to get the gem from a specific git checkout, like so:
gem "devise", :git => "git://github.com/plataformatec/devise.git", :branch => "v1.0"
If you use the
:ref option, your git gem will always use that commit, and will never be updated. However, if you use the
:branch option (or don’t supply any of the three checkout options), the
bundle install command will update the git gem to the latest revision of the given (or
C extensions that are specified in the
.gemspec file inside the repository will be compiled and installed. Executables in the .gemspec will be installed for use via
bundle exec executable.
If the git repository that you supply has a
.gemspec file in it, you don’t need to put a version number on the
gem line in the Gemfile. However, if there is no
.gemspec file, you will need to specify a version so that bundler can generate a
.gemspec file that uses default gem conventions.
Occasionally, the machines you deploy your application to are not able to connect to internet servers, including the Rubygems server. (Blocking outgoing connections from application servers is a somewhat common approach to security.) In that case, you will need to package up the
.gem files for all the gems your application needs to run with the
bundle package command.
Once you have run the command, all the
.gem files will be deposited into the
vendor/cache/ directory. Add those files to git and commit them, and on your next deploy,
bundle install will simply use those gems instead of looking for them on
Advanced: Installing to vendor
If you develop on the same architecture that you deploy onto, it is even possible to fully install every gem into your application directory to be checked in to source control. The command to do this is
bundle install vendor. After running it, you can check the entire
vendor/ directory in to your source control, and
bundle install will no longer install anything.
However, this is not a recommended option. It can save installation time, but lead to problems if another developer (or another server you eventually deploy onto) needs to compile native extensions for a different platform or architecture.
More Advanced Features
Bundler supports a number of other use-cases through features not described here. Its full feature-set is described on its official web site
As you can see, gem dependency management with Rails 3 is simple, yet effective. The bundler adds many new capabilities and features, while at the same time solving the gem conflict issues that Rails 2’s
config.gem could suffer from. If you have feedback, need help, or just want to chat about bundler, visit the IRC channel #bundler on Freenode.