We recently deployed a Rails 3 application that uses Bundler to manage dependencies. We freeze the gems in the application so it can be deployed on the same boxes as other applications that have different gems. It is best to start with a gemset with zero gems, then install only the bundler gem, then let bundler install everything else. Installing gems should be as simple as bundle install. Built gems will have a .gem file stored in vendor/cache. We tried a few options before getting things right with Bundler, and did notice some fixes related to freezing gems that were present in 1.0.12 which is what we’re using now.

Lock file

The lock file (Gemfile.lock) will write the specific version numbers of gems where version numbers were not already provided, as well as write out the name and version number of any gem that is declared as a dependency of a gem. In this way you know that your coworkers will get the right gems installed when they run bundle install. This is an improvement where different developers could have different versions of gems and not have any issues until runtime. I still specify the version number in the Gemfile explicitly, since it is an opportunity to check the version numbers in use in other applications, and I feel it is good practice to be aware of which versions are in use.

Config file

Sort of like the .git/config file which has some git repository metadata, the bundler config file will store some settings here. This file should not be version controlled. Contents of a .bundle/config file might look like the following.

--- 
BUNDLE_FROZEN: "1"
BUNDLE_DISABLE_SHARED_GEMS: "1"
BUNDLE_BIN: bin
BUNDLE_PATH: vendor/bundle

Bundler in practice

One of the most frequent problems team members have with bundler (especially where it is not used) is remembering to run executables with bundle exec in front of the command (when gems need to be loaded by bundler first). A rake command may need to load the Rails environment, and rails may be loaded by bundler, so bundle exec rake would be necessary instead of rake in that case.

The other problem is adding new gems in an application where they are all frozen. Previously I had been running bundle install with the --deployment option (it seems to have the same effect as package, i.e. building a .gem file in vendor/cache), but the bundler documentation says to not use --deployment on a development machine. However running bundle install first, then again with the --deployment option, fixes the issue.

The bundler documentation on packaging says to run bundle package to build the .gem files in vendor/cache.

Editing a gem locally

If you have local edits to a gem, you probably want to keep the source in a separate location from where bundler would put it (vendor/bundle). To store the gem source in another location, specify the --path option to bundle install, e.g. bundle install --path vendor/gems. Another option is to specify a git repository with the :git option on a per-gem basis in the Gemfile. In one case bundler downloads and builds a gem from a project fork on GitHub using this option in our project. We have a lot of internal gems behind the firewall using Gem in a box with the internal gem host added to the project Gemfile.

Binaries or other executables

Accessing binaries or other executables like Ruby scripts with Bundler is a little different. Bundler provides a --binstubs option which generates binaries for each one in the project. Refer to the bundler man page for more details. We used this option with Jammit (an asset packager) for a while and had to call bin/jammit from Rails root instead of just ./jammit.

Conclusion

I hope some of these tips help you get started or out of a jam with Bundler. Bundler had some critics early but it is an improvement over the previous method of managing dependencies for Ruby projects.