Channels ▼

Nick Plante

Dr. Dobb's Bloggers

Rails: Vendor Everything Just Got Easier

March 29, 2008

Here's a common deployment fiasco: You build something. Something great. You use a number of different third party libraries installed on your system. Then, when you deploy the app to production, things break. You investigate. You realize that one of the libraries you're depending on doesn't exist on the server. You install it. Things still don't work. You realize that another one of the third party libraries is an older version. You update it. Things start to work. But now, one of the other applications hosted on that same server stops working, because some feature it was depending on in the older library is not available in the new version.

Eek. Guess it's time to "vendor everything"...

Keeping system-wide libraries like Ruby Gems in sync between development and production environments is of the utmost importance, and failure to do so can lead to many a crying fit or late night nervous breakdown. The same problem, of course, exists when multiple developers are working on the same project. In Rails, the solution is to explicitly list those dependencies in your project and to unpack any Gems you're using into the project's vendor directory so they can be loaded in place of the system-wide Gem versions. This strategy has been termed vendor everything and includes other benefits as well, including the ability to get a version of your app up and running just about anywhere with minimal fuss.

Since this wasn't a native feature of the framework, a few different approaches evolved including Dr Nic's GemsOnRails plugin, GemInstaller, and the FrozenGemsGenerator. However, recent changes in Rails core have made this easy to do right out of the box.

Today, in Rails Edge, you can take advantage of these features by adding Gem requirements directly to your config/environment.rb:

{geshibot lang="ruby"}
Rails::Initializer.run do |config|
config.gem "money"
config.gem "chronic"
config.gem "hpricot", :version => '0.6', :source => "http://code.whytheluckystiff.net"
end
{/geshibot}

With this in place, you can now list required gems (money, chronic, and hpricot) using the new rake gems task. The output will also indicate whether or not the gem is installed locally. You can install missing gems using rake gems:install and unpack the gems into the vendor/gems directory using rake gems:unpack:

 

<br />$ rake gems:unpack GEM=money          <br />Unpacked gem: '/Users/nap/dev/edgetest/vendor/gems/money-1.7.1'<br />

 

A simple improvement, sure. But one that is bound to save some of us countless hours and make deployment far more pleasant in general. Once the gems are unpacked, they'll be automatically added to the Rails load path when your server is started, so the right libraries (and the right *versions* of those libraries) will be present for your app. Note that this isn't a 100% solution however; unpacking some gems, particularly those that have native bindings like Hpricot and RMagick, may add some unavoidable complication here. That said, it still helps to mitigate a serious pain point.

In any case, this is just one of the many new features in Rails Edge, which I'd encourage you to check out if you're a Ruby developer. Related features include the ability to specify gem dependencies for plugins and allow gems to be used as plugins. Other recent advances are covered elsewhere by Ryan Daigle, Caboo.se, and the Rails Envy team.

This should all be bottled up into the Rails 2.1 release sometime in the near future, but as always, feel free to freeze your Rails project to edge (rake rails:freeze:edge) if you want to take an early look at what's coming!

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 


Dr. Dobb's TV