rails/rails — pull request #7755 by saimonmoore (2012-09-25 13:56:47+00:00)
Title: Loading pattern for connection adapters that plays nicely with bundler --standalone

Hi

I'm using the relatively new --standalone feature/option of bundler so as to avoid extracting a part of my rails project into a separate project. My only requirement is to not have to load rails entirely:

By creating a custom gemfile (subset of your typical gemfile) and executing:

bundle install --gemfile=Gemfile.my_subset --standalone

bundler will create a ruby script which requires all the gems in your gemfile subset using the
original gems locations.

e.g. :

path = File.expand_path('..', __FILE__)
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/rake-0.9.2.2/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/multi_json-1.0.4/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/activesupport-3.1.6/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/builder-3.0.3/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/i18n-0.6.0/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/activemodel-3.1.6/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/arel-2.2.3/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/tzinfo-0.3.33/lib")
$:.unshift File.expand_path("#{path}/../ruby/1.9.1/gems/activerecord-3.1.6/lib")
...

This allows scripts to e.g. load just activerecord without setting up a separate
gemfile.

The issue here is that with this setup script, you aren't using bundler (to avoid loading rails and
the gems in your typical gemfile.). Additionally, the gems the script requires are `expanded` gems
and have not been installed via `gem install`.

Activerecord connection adapters have this code:

gem 'mysql2', '~> 0.3.10'
require 'mysql2'

This code assumes:

* You're running the code within bundler (recommended)
* You have the mysql2 gem installed as a gem in your system

When using bundler standalone neither of these cases are true so the app breaks with:

Please install the mysql2 adapter: `gem install activerecord-mysql2-adapter` (no such file to load -- active_record/connection_adapters/mysql2_adapter)
because it hits the 'gem' call before it attempts to require 'mysql2'

IMHO a better approach would be:

begin
require 'mysql2'
rescue LoadError
gem 'mysql2', '~> 0.3.10'
require 'mysql2'
end

This code assumes you already have mysql2 on your load path somehow and only if it raises an exception do we attempt to issue the `gem` call.

Is this reasonable?

I've coded up the changes against 3-1-stable (which is what we're using in production) but I can easily backport it to master (elsewhere) if people see this as a good idea.

I had the same test failures before and after my changes: https://gist.github.com/3782040 (I tested sqlite3 and mysql/2)

Regards,

Saimon

Note: See issue https://github.com/rails/rails/issues/7753 for original discussion.