Bundler Pro Tips

Bundler has been out for over a year now. Many people have adopted Bundler as their development tool of choice to handle dependencies. At Engine Yard we sometimes encounter customers who haven't yet made the switch to Bundler. While some of these folks are unable to because of development priorities, some actually actively reject Bundler. These rejections surprise me since Bundler is such a functional tool.

I'm going to walk you through some key benefits of Bundler. Then, I'll answer some Bundler questions and concerns to leave you with a better understanding of Bundler so you can use it better day to day.

Key Benefits

  1. Version Consistency
    Ensuring your developers are all working with the same version of things can be very challenging. One of the great things about Bundler is that it allows you to ensure that all machines are running the same versions of gems AND their dependency while at the same time giving you a simple path to update one or two of your gems.
  2. Dependency Resolution
    If you've ever come across an error like this: can't activate rack (~> 1.0.1, runtime) for [], already activated rack-1.0.0 for [], then you know how hard it can be to debug. You need to figure out which gem requires the older version, which gem requires the newer version, and then (usually through trial and error) determine which rack version satisfies the dependency of both. Bundler solves this challenge.
  3. Development Freedom
    Does your application depend on a gem that you are developing? You used to stick it in vendor/gems or maybe even used git submodules. Now it's as simple as forking the gem and passing the :git parameter to your gem. No more committing large swaths of files to your repo just because your app relies on them.

Now that I've given the brief overview of some of Bundler's benefits I hope it's apparent how useful it is. It's as simple as adding a gem to your gemfile and running bundle install. If you're using Rails 3 you're already using Bundler, so go right ahead.

Your Questions

A few weeks ago we asked you to suggest challenges encountered using Bundler, or common hesitations to using Bundler. Here's what you came up with.

How do I run code in one bundle from code in a different bundle? (via @joshsusser)

Good question. This isn't heavily documented.

It all comes down to this method: Bundler.with_clean_env { #do stuff }.

This resets your env to what it was before you called the require to bundler/setup. This will clear out the env['BUNDLE_GEMFILE'] and allow you to use a different Gemfile. Here Andre Arko shows how this works, and what to expect from running code within a Bundler.with_clean_env block.

How do I avoid fetching source index every time? (via @Pistos)

There is a flag you can pass to bundle install that does this: bundle install --local.

According to the docs, the local flag does this:

Do not attempt to connect to rubygems.org, instead using just the gems located in vendor/cache. Note that if a more appropriate platform-specific gem exists on rubygems.org, this will bypass the normal lookup.

When should I run bundle install vs. bundle update? (via @jamiecobbett)

Always run bundle install. Run bundle update only if you actually wish to update a gem, or if bundle install warns you that you need to update a gem. You can also conservatively update gems with bundle update #{gemname} which will keep everything else at the same version but re-resolve the dependency with the newer version of the gem you want to update. The implication of bundle install is that you want to change only the things that you changed in the Gemfile and any non-shared dependencies. If a dependency of a gem you change is a dependency of another gem, the bundle install will fail and actually warn you to update.

Is Bundler compatible with Ruby 1.9.2? (via @vandrijevik)

Yes. Bundler is fully compatible with Ruby 1.9.2.

How can I use Capistrano with Bundler? (via @smathy)

You can add require 'bundler/capistrano' to the top of your deploy.rb. This adds the bundle install task to run after every deployment. By default this runs a bundle install with the --deployment and --quiet flags as well as without the development and test groups. It installs the bundle to shared/bundle. You can override these defaults by setting any of these in your deploy.rb.

    set :bundle_gemfile,  "Gemfile"
    set :bundle_dir,      File.join(fetch(:shared_path), 'bundle')
    set :bundle_flags,    "--deployment --quiet"
    set :bundle_without,  [:development, :test]
    set :bundle_cmd,      "bundle" # e.g. "/opt/ruby/bin/bundle"
    set :bundle_roles,    #{role_default} # e.g. [:app, :batch]

What can I do about the indirection Bundler adds to the command line? For example, bundler exec foo instead of simply foo (via @peteraronoff)

Unfortunately you need at least a little indirection or there wouldn't be a way to keep track of which gems you need to activate. Here are some tricks you can use to minimize the indirection as much as possible.

  1. alias b=”bundle exec”
    This makes it easy to run most bundled commands, for example "b rails c".
  2. bundle exec bash
    You can bundle exec into bash (or zsh or whatever you favorite shell is) and have the shell executed within the bundle environment. This allows you to run binary gems from the command line without having to bundle exec.
  3. bundle install --binstubs
    This will install bin files into the bin/ directory of your app. Now you can run bin/rspec or bin/executable and it will be run within the bundle environment.

Why is there is a platform option for Windows, but not Darwin? (via @soederpop)

Windows is a Ruby platform. Darwin is an operating system that the ruby interpreter runs on. For now, use groups.

I'm interested in some examples for 'bundle pack.' I find this command useful to deploy to machines off the network. (via @hoxworth)

Simple Example: bundle pack && git add vendor/cache && git commit -am “Packed gems” && git push && cap deploy

You can use this as a drop in replacement for vendor/gems, with the added benefit of knowing that even gems depended on will be consistent across platforms. Keep in mind this doesn't work with gems from git yet, though.

Any performance issues with switching from Bundler 0.9.26 to 1.0.7? I'm seeing an odd behavior with higher CPU usage on prod server. (via @ttdonovan)

Currently there are no other reports of performance issues. Please file an issue with the steps to reproduce and the developers can look into it for you. The simpler the issue is to reproduce, the easier it will be to track down.

Does Bundler work on Windows? (via @drnic)

Yes, Bundler does work on Windows. There is a known issue regarding lockfiles and multi-platform use of Bundler. If you use Bundler on Windows and Mac or Linux systems, and run bundle install on the Windows machine the lockfile gets generated specifically for Windows. For now, the recommendation is to run bundle install on a machine that closely resembles your deployment setup and commit that lockfile into the repository.

Other Questions?

What other hesitations or frequently encountered issues have we missed? Leave them in the comments section and we'll do our best to tackle them too.

To learn more about Bundler visit the Bundler website. You can also fork Bundler on GitHub.