Question

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
Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top