Freeze (vendor, unpack) a single Ruby gem with and without Bundler

When you need to patch an existing gem, one way is to "vendor" the gem by copying it into the vendor/gems directory of your Rails project. You can then make any changes you require and Rails will use the vendored version of the gem after a server restart. Unfortunately you need to perform some additional steps to marry Rails and the copied gem. This notes describes what to do.

With Bundler

This is super-painful. If you just copy the gem to vendor/gems, Rails will complain:

Unpacked gem foolib in vendor/gems has no specification file. Run 'rake gems:refresh_specs' to fix this.

Unfortunately, rake gems:refresh_specs will not do anything. Here is what you need to do:

  1. Copy the gem from /usr/lib/ruby/gems/1.8/gems/foolib-1.2.3 to vendor/gems/foolib-1.2.3. Make sure the folder name actually ends in ...-1.2.3.
  2. cd to the gem. Check if a foolib.gemspec exists. If it doesn't, run rake gemspec:generate
  3. Run gem build foolib.gemspec . This will create a foolib-1.2.3.gem package in the current directory.
  4. Run gem specification foolib-1.2.3.gem > .specification . This will extract the YAML metadata from the gem package and create the missing .specification file.
  5. We no longer need the gem package: rm foolib-1-2-3.gem

Now that you have a working gem in vendor/gems, you need to tell Bundler about it. In your Gemfile, change the gem's line to:

gem 'foolib', :path => File.join(File.dirname(__FILE__), '/vendor/gems/foolib-1.2.3')

Now run bundle install --local to update your Gemfile.lock. It should work now.

Fun fact: Our install-gems-remotely script is aware of vendored gems and will scp-copy them to the remoty server.

Without Bundler

Don't use gem unpack since the gemspec will be missing. Use this instead:

rake gems:unpack GEM=cucumber_factory RAILS_ENV=test
Henning Koch Over 13 years ago