Bundler and Rubygems Again
Posted by Christopher Rigor on February 16, 2010
Filed Under Ruby on Rails
On my previous post, I showed you how to use bundler with rails 2.3.5. Bundler is used to install the gems, and rubygems is used to load the gems. Bundler as of version 0.9.4 doesn’t work with rails 2.3.5.
Since rubygems is used to load the gems, you might still encounter dependency resolution issues. This situation is described in the readme of bundler. Let’s say you have the following gems
actionmailer 2.3.4
activemerchant 1.5.0
activesupport 2.3.5, 2.3.4
Activemerchant needs activesupport >= 2.3.2. When you require activemerchant, it will activate the latest version that meets that requirement which is 2.3.5. Actionmailer on the other hand needs activesupport = 2.3.4. When rubygems tries to activate activesupport 2.3.4, it will raise an error.
$ irb irb(main):001:0> require 'rubygems' => true irb(main):002:0> gem 'activemerchant' => true irb(main):003:0> gem 'actionmailer' Gem::LoadError: can't activate activesupport (= 2.3.4, runtime) for ["actionpack-2.3.4", "actionmailer-2.3.4"], already activated activesupport-2.3.5 for ["activemerchant-1.5.0"] from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:280:in `activate' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:296:in `activate' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `each' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `activate' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:296:in `activate' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `each' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `activate' from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:68:in `gem' from (irb):3 irb(main):004:0>
Even if bundler installs the correct versions to vendor/bundler_gems, the presence of activesupport 2.3.5 in the system will cause an error. Another solution I tried is managing the load path by hand.
On config/preinitializer.rb
bundler_gems = File.expand_path('../../vendor/bundler_gems/gems', __FILE__)
if File.exist?(bundler_gems)
Dir["#{bundler_gems}/*/lib"].each { |path| $:.unshift(path) }
end
This works if you use require instead of gem.
$ irb
irb(main):001:0> bundler_gems = File.expand_path('/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems')
=> "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems"
irb(main):002:0> if File.exist?(bundler_gems)
irb(main):003:1> Dir["#{bundler_gems}/*/lib"].each { |path| $:.unshift(path) }
irb(main):004:1> end
=> ["/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/actionmailer-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/actionpack-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activemerchant-1.5.0/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activerecord-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activeresource-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activesupport-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/builder-2.1.2/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/bundler-0.9.5/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rack-1.0.1/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rails-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rake-0.8.7/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/sqlite3-ruby-1.2.5/lib"]
irb(main):005:0> require 'rubygems'
=> true
irb(main):006:0> require 'active_merchant'
=> true
irb(main):007:0> require 'action_mailer'
=> ["MailHelper", "Text", "ActionMailer"]
$ irb
irb(main):001:0> bundler_gems = File.expand_path('/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems')
=> "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems"
irb(main):002:0> if File.exist?(bundler_gems)
irb(main):003:1> Dir["#{bundler_gems}/*/lib"].each { |path| $:.unshift(path) }
irb(main):004:1> end
=> ["/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/actionmailer-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/actionpack-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activemerchant-1.5.0/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activerecord-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activeresource-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/activesupport-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/builder-2.1.2/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/bundler-0.9.5/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rack-1.0.1/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rails-2.3.4/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/rake-0.8.7/lib", "/Users/crigor/admoolabs/labs/vendor/bundler_gems/gems/sqlite3-ruby-1.2.5/lib"]
irb(main):005:0> require 'rubygems'
=> true
irb(main):006:0> gem 'activemerchant'
=> true
irb(main):007:0> gem 'actionmailer'
Gem::LoadError: can't activate activesupport (= 2.3.4, runtime) for ["actionpack-2.3.4", "actionmailer-2.3.4"], already activated activesupport-2.3.5 for ["activemerchant-1.5.0"]
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:280:in `activate'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:296:in `activate'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `each'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `activate'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:296:in `activate'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `each'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:295:in `activate'
from /opt/local/lib/ruby/site_ruby/1.8/rubygems.rb:68:in `gem'
from (irb):7
from /opt/local/lib/ruby/1.8/i686-darwin10/rbconfig.rb:132
Require works because I added the lib/ directories to the load path. If a file exists on the load path, require will not activate the gem. It will just load the file. If gems use gem ‘activesupport’ before require ‘active_support’, then we’ll be in trouble. This is not the ideal solution I’m looking for but it’s close. On my next post, I’ll discuss using ‘fake’ rubygems.