Read more

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

Henning Koch
February 01, 2011Software engineer at makandra GmbH

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

Illustration web development

Do you need DevOps-experts?

Your development team has a full backlog? No time for infrastructure architecture? Our DevOps team is ready to support you!

  • We build reliable cloud solutions with Infrastructure as code
  • We are experts in security, Linux and databases
  • We support your dev team to perform
Read more Show archive.org snapshot

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
Posted by Henning Koch to makandra dev (2011-02-01 18:53)