Yehuda Katz is a member of the Ember.js, Ruby on Rails and jQuery Core Teams; his 9-to-5 home is at the startup he founded, Tilde Inc.. There he works on Skylight, the smart profiler for Rails, and does Ember.js consulting. He is best known for his open source work, which also includes Thor and Handlebars. He travels the world doing open source evangelism and web standards work.

The How and Why of Bundler Groups

Since version 0.9, Bundler has had a feature called “groups”. The purpose of this feature is to allow you to specify groups of dependencies which may be used in certain situations, but not in others.

For instance, you may use ActiveMerchant only in production. In this case, you could say:

group :production do
  gem "activemerchant"
end

Specifying groups allows you to do two things. First, you can install the gems in your Gemfile, minus specific groups. For instance, Rails puts mysql and pg in a database group so that if you’re just working on ActionPack, you can bundle install --without db and run the ActionPack tests without having to worry about getting the gems installed.

Second, you can list specific groups to autorequire using Bundler.require. By default, Bundler.require requires all the gems in the default group (which is all the gems that have no explicit group). You can also say Bundler.require(:default, :another_group) to require specific groups.

Note the difference between these operations: bundle install is opt-out, while Bundler.require is opt-in. This is because the common usage of groups is to specify gems for different environments (such as development, test and production) and you shouldn’t need to specify that you want the “development” and “test” gems just to get up and running. On the other hand, you don’t want your test dependencies loaded in development or production.

It is also worth noting that all gems that you installed (i.e. not the ones that you excluded at install time with --without) will be available to require. This has no effect unless you actually require them. This means that in development mode, if you explicitly require rspec, it will work.

Rails 3 defaults to mapping groups to environment names, and explicitly autorequiring the implicit default group and the group named the same as the current environment. For example, in development mode, Rails will require the default group and the development group. The code that does this is in your application.rb:

Bundler.require(:default, Rails.env) if defined?(Bundler)

Consistency

In order to ensure consistency across all environments, bundler resolves the dependencies of your application using the gems listed in all groups, even if you specify --without. This means that while you can skip installing the gems listed in the production group by saying --without production, bundler will still download and examine the gems in order to properly resolve all dependencies.

As a result, the dependencies you install in development mode and test with will be compatible with the gems in other environments. In essence, this policy ensures that if your tests pass and run in development, your app will not fail to run in production because the dependencies resolved differently.

Multiple Inconsistent Configurations

Sometimes, especially when developing gems for wider use, you want to test your code against multiple incompatible configurations. At first glance, you might think that you could use groups for this case, but as described above, groups are designed for cases where all of the gems are compatible, but you don’t always want to have to install them in all situations.

Instead, use multiple Gemfiles, one for each incompatible configuration. When installing, do bundle install --gemfile Gemfile.rails2. This will tell Bundler to use Gemfile.rails2 rather than the default Gemfile. As in all cases in Bundler, you can also specify this option globally with an environment variable (BUNDLE_GEMFILE).

11 Responses to “The How and Why of Bundler Groups”

THANKS ! :)

Ahhhh! Now I finally understand! Thanks for this post!

Yehuda, how to specify several –without groups? “–without test –without development” and “–without test,development” doesn’t works.

Ok, it’s “–without test:development”.

Hi Yehuda, I have a Rails 2.3.8 app that I would like configure so that groups are opt-in. Adding the following to my application.rb doesn’t seem to make a difference ‘Bundler.require(:default, Rails.env) if defined?(Bundler)’ does this only work in Rails 3?

Thanks for the useful info. A couple questions:
(1) Is –gemfile documented anywhere? I didn’t see this on http://gembundler.com/
(2) Why is there a command line switch for “install” but not “require”? For example, on a production system I may want to install required gems via the command line without having to exclude everything else. Or am I thinking about it wrong?

Hi Yehuda,

I have a development team which uses linux, and mac. The mac developers depend on autotest-fsevent and autotest-growl which have native dependencies on the mac.

I thought to use the platforms option, but it doesn’t include darwin. It does include mswin though.

How would you suggest we go about working together smoothly? I’m sure I’m overlooking something obvious

@Jonathan:

I think RubyGems takes care of all that for you… “gem install autotest-fsevent” should figure out which platform you are on automatically, regardless of bundler. It’s just a wrapper for RubyGems anyway. Also, use autowatchr for testing. Much simpler and configurable than autotest. It already hooks into fsevent. No Growl support yet though :(

- Adam

@AlekSi: To install without multiple groups you need to use “bundle install –without development test”

(I know this is an old post, but just wanted to correct that for the future readers)

@Adam Grant
That’s wishful thinking. Currently having an issue with hpricot wanting to install Linux version on Windows unless you specify platform.

Thanks for the info. This really sucks, I have to comment the production gems like mysql2 on my development machine every time (because the mysql2 can not be installed on OS X). Since the first mysql gem the JAR hell from Java has reached rails developers and there is no way out (like groups in the gemfile that would only be loaded on a given environment)…

Leave a Reply

Archives

Categories

Meta