Bundler makes contributing to ruby gems easier

After using Bundler for the past few months, I love it. It turns managing project dependencies and deployment into a piece of cake. However after coming across a particular dependency declaration, something clicked in my head that made me like it even more.

A common scenario

Imagine the following scenario: you’re booking it on your current project and encounter a bug with a dependency. While some of you may immediately wince thinking this could be an indeterminate yak-shave, this is actually a great opportunity to contribute back to the community AND keep your project on course.

Tools like Github make it dead simple to fork an Open Source project to make your changes, but then you’re left figuring out how to bring your change back into your project. Do you write a monkey patch and stuff it into RAILS_ROOT/lib? Do you roll your own private gem, install it locally, pass it to the other devs, install it on production…yuk. In the past these pains would actually get in the way of what I was originally doing: working on my project.

How to contribute and keep your project moving forward

Bundler offers this great git dependency declaration:

  gem "nokogiri", :git => "git://github.com/tenderlove/nokogiri.git"

Or if you want to be more specific to a branch:

  gem "nokogiri", :git => "git://github.com/tenderlove/nokogiri.git", :branch => "some_branch"

So how does this relate to fixing your issue and giving back to the community? Well it’s actually pretty simple.

  1. First locate the project on Github.
  2. Fork it as your own project. If you don’t have a Github Account, quit reading and sign up for free now.
  3. Clone the project and make the relevant changes. Make sure all tests are passing and/or any other contributing guidelines that the maintainer posts.
  4. Send a pull request back to the maintainer of the project. Sometimes projects prefer you to open a Github Issue within the project, so check out the details on a per project basis.

At this point you’ve successfully submitted a change and it’s up to the maintainer to pull it in. It’s not always guaranteed the patch will be accepted, but it’s a great start. Any contribution, even if it’s inefficient or breaks the tests, is better than no contribution at all. At least it starts a dialogue.

Now for the easy part, integrating the change back into your project. Update your Gemfile and change the gem dependency to:

  gem "gem_name", :git => "git://github.com/your_github_username/your_fork.git"

or if you have your changes in a different branch other than master:

  gem "gem_name", :git => "git://github.com/your_github_username/your_fork.git", :branch => "branch_that_includes_fix"

Now you can keep moving on your project. Most of the time you’ll be notified by the author if the changes were pulled in, or similar changes. And once it has pushed to RubyGems you can switch back to the gem as a dependency.

We're already doing it

Example 1: We’re using sunspot_index_queue for one project, which is a way to keep the Sunspot/Solr index updates separate from the Web request/response cycle (blog post coming soon). I encountered an issue with the Mongo storage code, and followed. the steps. above. in order to keep moving on the project.

Example 2: At CollectiveIdea we’re big fans of MongoDB and mongo_mapper which we’re consistently pushing updates to. It’s not uncommon to see this in our Gemfile:

  gem 'mongo_mapper', :git => 'https://github.com/collectiveidea/mongomapper.git'

I love it when it’s this easy to solve your own problem and potentially other people’s problems as well.