While attempting to upgrade our local bundler version to 1.9.6, we ran across a few issues that others may also experience when dealing with a mature Ruby/Rails application. As of version 1.9.0, bundler upgraded their internal dependency resolver to use Molinillo, the same dependency resolver used by the Cocoapods dependency manager for Swift and Objective-C. This change may yield unusual errors when running bundle install:

Resolving dependencies...........................

Your Gemfile requires gems that depend on each other, creating an infinite loop.
Please remove gem 'XXX' and try again.

Or:

Resolving dependencies....

Bundler could not find compatible versions for gem "mini_magick":
  In Gemfile:
    some_gem (>= 0) ruby depends on
      another_gem (~> 1.0.0) ruby depends on
        mini_magick (~> 3.6.0) ruby

Gross. What’s the problem?

A matter of source

Most Gemfiles probably contain just one source line at the top of the file (for example: source "https://rubygems.org"), that tells Bundler where to go to look for gems defined in the Gemfile. If all the gems come from a single source, no problems will come up, but we at Lumosity have multiple sources defined. Not only do we have rubygems.org as a source, but we also have private gem repos as well. Bundler will warn of these multiple sources:

$ bundle install
Warning: this Gemfile contains multiple primary sources. Using `source` more than
once without a block is a security risk, and may result in installing unexpected gems.
To resolve this warning, use a block to indicate which gems should come from the
secondary source.
To upgrade this warning to an error, run `bundle config disable_multisource true`.

So what’s the best thing to do? Start using source blocks, as defined in the bundler manual.

Here is a simplified example of our Gemfile without source blocks:

1
2
3
4
5
6
7
8
source 'https://rubygems.org'
source 'http://rails-assets.org'
source 'https://private-gem-repo-example.org'

gem 'jquery-rails'
gem 'rails'
gem 'rails-assets-underscore'
gem 'some_gem'

And now with source blocks:

1
2
3
4
5
6
7
8
9
10
11
12
source 'https://rubygems.org'

source 'http://rails-assets.org' do
  gem 'rails-assets-underscore'
end

source 'https://private-gem-repo-example.org' do
  gem 'some_gem'
end

gem 'jquery-rails'
gem 'rails'

With the addition of source blocks in our Gemfile, bundler can find gems in their respective repositories, and resolve their dependencies with ease.

Note: We kept source ‘https://rubygems.org’ at the top of the Gemfile to serve as the default gem repo for Bundler. There is no need to use source blocks when it’s the default/highest priority source.