Bundler in practice

We recently deployed a Rails 3 application that uses Bundler to manage its dependencies. We freeze the gems in the application so it can be deployed on the same boxes as other applications, that have different gem depdencies. It is best to start with a RVM gemset with zero gems, and install only the bundler gem, then let bundler install everything else. The pitch is 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 as of this writing.

Lock file

The lock file (Gemfile.lock) will write in the specific version numbers of any gems if they aren't 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 Gemfile. In this way you know that your coworkers will get the right gems installed when they run bundle install. I still specify the version number in the Gemfile though 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 in 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 when they clone a new project, particularly if the other project is not using bundler, is remembering to run executables with bundle exec before the executable name, if the program requires gems be loaded by bundler first. A rake command might need to load the Rails environment for example, and rails may be loaded by bundler, so bundle exec rake may be necessary instead of just rake.

The other problem is adding new gems in an application where they are all frozen. Previously I had been running bundle install with --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. Bundler seems to enforce that the --deployment option uses the local source to build from.

Going forward the bundler documentation on packaging says to run bundle package to build the 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 level in Gemfile. In one case bundler downloads and builds a gem from a project fork on github using this option in our project.

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.

0 comments

Comments are closed.