views:

210

answers:

2

I could really use another set of eyes on this so I thought I would post it here. A while ago I wrote a basic ActiveRecord Extension for my own educational purposes. I've been reading about Railties lately and thought I would try to get it working with Rails 3. I thought I would package it up as a gem to get a sense of that process as well. If I skip the Railtie and just do this as a traditional monkeypatch in the initializers folder it works fine. Using a Railtie... nothing.

From the looks of it my Railtie is never executed and therefore nothing else seems to be happening.

Does anyone see anything wrong here?

Any suggestions for best practices or improvements are also welcome.

project Gemfile:

gem 'sql_explain', :path => "/home/mike/projects/sql_explain/"

gemspec:

...
  spec.files = %w(README.rdoc sql_explain.rb lib/sql_explain.rb lib/railtie.rb sql_explain.gemspec)
...

sql_explain.rb

require 'lib/railtie.rb'

railtie.rb

require 'active_record'
require 'sql_explain'

module SqlExplain
  class Railtie < Rails::Railtie
    railtie_name :sql_explain
    initializer 'sql_explain.extend.activerecord' do
      if defined?(ActiveRecord)
        ActiveRecord::ConnectionAdapters::MysqlAdapter.include SqlExplain::AR
      end
    end
  end
end

sql_explain.rb

module SqlExplain
  module AR
    def self.included(base_klass)
      base_klass.send :alias_method_chain, :select, :explain
    end


    def select_with_explain(sql, name = nil)
      @connection.query_with_result = true
      result = execute('explain ' + sql, :skip_logging)
      rows = []
      result.each_hash { |row| rows << row }
      result.free
      @connection.more_results && @connection.next_result    # invoking stored procedures with CLIENT_MULTI_RESULTS requires this to tidy up else connection will be dropped
      exp_string = ""
      rows.each{|row| row.each_pair{|k,v| exp_string += " #{k}: #{v} |"}}
      log(exp_string, "Explanation") {}
      select_without_explain(sql, name)
    end
  end
end
A: 

Are you sure this is true?:

if defined?(ActiveRecord)

I suppose it is false. Instead of "rails" try to require "rails/all" - the first one is not loading AR.

gertas
Thanks gertas, I took another look at the requires and I think I have it doing the right thing now... maybe.
Mike Williamson
+2  A: 

Looks like you've already got this sorted out, but remember that with Rails 3 you can do:

ActiveSupport.on_load :active_record do
  ActiveRecord::ConnectionAdapters::MysqlAdapter.include SqlExplain::AR
end

That'll ensure that your include will only be fired once ActiveRecord has been loaded.

PreciousBodilyFluids
I could never get the initializer method to fire in my railtie. Any tips on that?
Mike Williamson
Nothing pops out at me as being wrong with it. Are you sure the Railtie itself is loading?
PreciousBodilyFluids
The railtie is. ActiveSupport.onload inside the railtie is working with no troubles. Anything inside an initializer block never fires. The docs make it seem like is just gets called automatically...
Mike Williamson