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.

Comments

blog comments powered by Disqus