I was recently called for help to update a gem in a Rails application I wrote a couple of months ago. It was important to only update a single gem (which had a known security vulnerability) and not touch any others, as this would have triggered a complete cycle of QA.

Unfortunately, I cannot share the full Gemfile, but I’ve found a similar example in an application I’m currently working on: sidekiq with its dependencies on concurrent-ruby and redis. The Gemfile.lock looks like this:

sidekiq (4.1.1)
  concurrent-ruby (~> 1.0)
  connection_pool (~> 2.2, >= 2.2.0)
  redis (~> 3.2, >= 3.2.1)
...
concurrent-ruby (1.0.1)
redis (3.2.2)
sidekiq (4.1.1)

Everybody that has been in the same situation knows that a bundle update will not yield the desired result as it will update all the dependencies.

bundle patch

The awesome folks at LivingSocial have released a project called bundler-patch which updates your gems conservatively.

Before we go into more details, let’s see if it gives us the desired result. First, we need to install it via gem install bundler-patch and then run bundle patch sidekiq.

Here’s the extract of our Gemfile.lock:

concurrent-ruby (1.0.1)
redis (3.2.2)
sidekiq (4.1.2)

Awesome! It only updated sidekiq to version 4.1.2.

The explanation? As opposed to bundle update, which will try to get the latest version of all your gems and its dependencies, bundler-patch will prefer the latest release from the current version of the gem. Be sure to check out their README for the full description and additional options!

Bonus: Why bundle update --source does not (reliably) work

There are various blog posts and Stack Overflow articles suggesting that bundle update --source will only update the gem specified. Let’s try it out: bundle update --source sidekiq:

concurrent-ruby (1.0.1)
redis (3.3.0)
sidekiq (4.1.2)

Yikes - we didn’t update concurrent-ruby, but redis was still updated to 3.3.0. Why is that? @neoeno describes the current behavior in a comment on a pull request dealing with the –source option:

Passing a gem to the source option will update a gem and all of its dependencies except those that are specified elsewhere in the Gemfile or are depended on by other gems.

That means that updates with --source will work fine for gems with popular dependencies and on larger projects.