What's New in Edge Rails: Gem Dependencies

Posted by ryan
at 4:43 PM on Tuesday, April 01, 2008

Rails plugins are great for many reasons, one being that they provide extra functionality without being an external dependency – they’re packaged right there with your application. Until recently, there was no way do programmatically define a Rails applications’ external gem dependencies and we were left with rolling our own gem dependency solutions.

That all changes with a nice way to define, and tie, gem dependencies to our Rails apps. In our environment.rb we have the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Rails::Initializer.run do |config| 

  # Require the latest version of haml
  config.gem "haml"

  # Require a specific version of chronic
  config.gem "chronic", :version => '0.2.3'

  # Require a gem from a non-standard repo
  config.gem "hpricot", :source => "http://code.whytheluckystiff.net"

  # Require a gem that needs to require a file different than the gem's name
  # I.e. if you normally load the gem with require 'aws/s3' instead of
  # require 'aws-s3' then you would need to specify the :lib option
  config.gem "aws-s3", :lib => "aws/s3" 
end 

So great – when your app loads up it will automatically find and require each of the gems you’ve listed. But what if you’re on a system that doesn’t have all of these gems installed, or you’ve just deployed to a fresh environment? There’s now a rake task that will install all the referenced config.gems on your target system:


rake gems:install

Before running this you can see what gem dependencies your app has by running rake gems.

However, this still doesn’t package these gem dependencies with the app, it only refers to system-dependent gems. If you want to pull these gems into your application source you can do so with the new rake gems:unpack task:

1
2
# Unpack all gems to vendor/gems
rake gems:unpack

You can also unpack individual gems:

1
2
# Unpack only the hpricot gem to vendor/gems
rake gems:unpack GEM=hpricot

This will unpack the gem into the vendor/gems/hpricot-0.5 directory which is automatically searched as part of the config.gem startup.

Your deployment strategy can now choose to automatically install required gems in each target environment or just package gems as part of the application source.

Update: Just added is the ability to build gems that have native extensions:


rake gems:build

tags: ruby, rubyonrails

Comments

Leave a response

  1. mustacheApril 01, 2008 @ 05:12 PM

    The beginning of the end of plugins.

  2. MattApril 01, 2008 @ 06:05 PM

    Ryan,

    Changeset #9148 means that what you should have there is:

    config.gem “haml”

    Rick pluralised on the first changeset :) The rake tasks are correct though, just those config’s

  3. Jim NeathApril 01, 2008 @ 06:07 PM

    The additions of gem dependencies into the rails core is probably one of my favourite additions recently.

    Brilliant stuff.

  4. RyanApril 01, 2008 @ 08:16 PM

    Matt – thanks for the proofread! I’ve updated the code to show the proper singularized form of config.gem.

  5. Loren JohnsonApril 01, 2008 @ 08:19 PM

    Brilliant indeed! ...and much needed.

  6. Dejan DimicApril 02, 2008 @ 02:40 AM

    Another great essential functionality. Bravo!!!!

  7. MattApril 02, 2008 @ 03:30 AM

    Ryan – not a problem :) Thanks for keeping us up to date with what’s happening on the edge!

  8. DadoApril 02, 2008 @ 03:36 AM

    great to see how “competing” projects (datamapper for partial sql updates and merb for gem dependencies instead of plugins) are helping rails get better!

  9. Jean-Michel GarnierApril 02, 2008 @ 05:47 AM

    Still using Rails 1.2.3 in my project and hopefully will upgrade to Rails 2.x in 2008. Hopefully, we are using geminstaller ( http://geminstaller.rubyforge.org/) With a simple YAML config file, here are the features:

    • Automatically install the correct versions of all required gems wherever your app runs.
    • Automatically ensure installed gems and versions are consistent across multiple applications, machines, platforms, and environments
    • Automatically add correct versions of gems to the ruby load path when your app runs (‘require_gem’/’gem’)
    • Automatically reinstall missing dependency gems (built in to RubyGems > 1.0)
    • Automatically detect correct platform to install for multi-platform gems (built in to RubyGems > 1.0)
    • Print YAML for “rogue gems” which are not specified in the current config, to easily bootstrap your config file, or find gems that were manually installed without GemInstaller.
    • Allow for common configs to be reused across projects or environments by supporting multiple config files, including common config file snippets, and defaults with overrides.
    • Allow for dynamic selection of gems, versions, and platforms to be used based on environment vars or any other logic.
    • Avoid the “works on demo, breaks on production” syndrome

    Chad Wooley used bdd and rspec, his test coverage is very good and he has cruisecontrol running for testing his library with all versions of rubygems!

    It works for any kind of ruby project.

  10. John TopleyApril 03, 2008 @ 03:37 PM

    I think it’s worth pointing out that those config.gem statements in environment.rb appear to be case-sensitive. I was getting an error with ‘bluecloth’ until I changed it to ‘BlueCloth’!

  11. Chris BaileyApril 08, 2008 @ 04:24 PM

    It also appears this doesn’t work for certain gems, where the name of the gem is different than the main file. For example, try the ruby-openid gem. That’s the name of the gem, but the library file is “openid.rb”. So, neither of the following work:

    config.gem ‘ruby-openid’ config.gem ‘openid’

  12. matthuhigginsApril 09, 2008 @ 03:14 AM

    When I do ‘rake gems:unpack’ I get the following error: uninitialized constant Gem::CommandManager

    The only gem defined in config is tzinfo, and I have v0.9.4 of ruby gems.

  13. RyanApril 11, 2008 @ 01:46 PM

    Matt – it spews all over the place when I try to run any of the rake tasks. Hopefully this is a temporary condition while things are still in development.

  14. Deepak JoisApril 12, 2008 @ 05:19 AM

    There seems to be a confusion regarding syntax

    config.gem “ferret”, :version => ‘0.11.6’

    works, whereas

    config.gem “ferret”

    does not work due to some latest changes in edge

  15. antonoApril 21, 2008 @ 12:25 PM

    Now possible on Edge:

    config.gem “ruby-openid”, :lib => “openid”, :version => “2.0.4”

    works fine for me

  16. softpropsMay 23, 2008 @ 10:37 PM

    This is again one of the reason to really LOVE Rails. This is one of the easiest, and fun, ways to resolve dependencies I’ve ever seen making relocating apps to different environments worry free and nearly effortless.

  17. Glenn GentzkeMay 28, 2008 @ 03:50 PM

    At my company we’ve modified our deploy scripts to handle all gems the application is dependent on that automagically installs them when needed. I love that it’s going to be baked right in! (even if it means letting go of our young deploy scripts)

  18. geroldJune 01, 2008 @ 07:56 AM

    good stuff, keep it coming ;-)

  19. JimmyJune 17, 2008 @ 04:35 PM

    When I run rake gems:install, I get the following:

    (in /u/apps/Manager/releases/20080617202021) Could not find RubyGem haml (= 2.1.0) Could not find RubyGem chronic (= 0.2.3) Could not find RubyGem hpricot (= 0.6) Could not find RubyGem scrapi (= 1.2.0) Could not find RubyGem activemerchant (= 1.3.2) rake aborted! no such file to load—haml

    (See full trace by running task with—trace)

    So it seems rails is trying to load one of my gems (haml) before it runs the rake task. What am I missing?

  20. usayesboygooJune 19, 2008 @ 09:01 PM

    pretty and we him. leaves they had a scientist. beechnuts We used I got then did

  21. sterling visaJune 24, 2008 @ 12:16 AM

    Nice Site! http://google.com

  22. thorny_sunJune 28, 2008 @ 11:20 PM

    just testing this out with an app that has the railspdf plugin that requires the pdf-writer gem. I purposefully uninstalled the pdf-writer gem to test. i get an error before the rake tasks can ever figure anything out. That’s because each of these rake tasks still set about loading up the plugins, and in this case this plugin is requiring the pdf-writer gem which then error. any idea how i would go about fixing this—or if it is even desirable to fix?—or if there is some workaround i’m missing?