2007
04.03

It’s a common question to extract programatically the SQL string that
was used in a AR query. I have found an ugly trick to do this. Here you
are:
After a whole bunch of cascading methods, a Post.find(1) is converted
into select_all("SELECT * FROM posts WHERE id=1") from the abstract
class.
Each adapter is overriding execute method wich invokes
@connection.query(sql) and @logger.


>> ActiveRecord::Base.connection.raw_connection.query("SELECT * FROM personnes WHERE id=1").class
=> Mysql::Result

Look at the Mysql::Result Class
Per default, AR write the @logger in a file.
Instead of writing in a file, you can ask @logger to output the result.


>> ActiveRecord::Base.logger = Logger.new(STDOUT)
=> #<Logger:0xb726e604 @formatter=nil, @level=0,
@default_formatter=#<Logger::Formatter:0xb726e5dc @datetime_format=nil>,
@progname=nil, @logdev=#<Logger::LogDevice:0xb726e5b4 @filename=nil,
@mutex=#<Logger::LogDevice::LogDeviceMutex:0xb726e58c
@mon_entering_queue=[], @mon_count=0, @mon_owner=nil,
@mon_waiting_queue=[]>, @dev=#<IO:0xb7cfc030>, @shift_size=nil,
@shift_age=nil>>
>> ActiveRecord::Base.clear_active_connections!
=> {}
>> Post.find(1)
  SQL (0.000089)   SET SQL_AUTO_IS_NULL=0
  Post Load (0.000174)   SELECT * FROM posts WHERE (posts.id = 1)-
=> #<Post:0xb72537c8 @attributes={../..}>

We can geek the logger. That’s pretty cool.
Look at the initialize method of Logger::LogDevice::LogDeviceMutex. It
asks:


  if log.respond_to?(:write) and log.respond_to?(:close)
    ../..
  end

But

>> @my_logger = ’’=> ”” >> @my_logger.respond_to?(:write)=> false>> @my_logger.class=> String

So you could add a write method in the String class:


>> class String
>>  def write(args)
>>    self.replace(args)
>>  end
>> end
=> nil
>> @my_logger.respond_to?(:write)
=> true
>> @my_logger.write('kikoo')
=> "kikoo"

You need actually also a close method:


>> class String
>>  def close(args=self)
>>    self.delete!(args)
>>  end
>> end
=> nil


>> ActiveRecord::Base.logger = Logger.new(@my_logger)
=> ../..
>> ActiveRecord::Base.clear_active_connections!
=> {}
>> Post.find(1)
=> #<Post:0xb725ab68 @attributes={../..}>
>> @my_logger
=> "  \e[4;36;1mPost Load (0.000667)\e[0m   \e[0;1mSELECT * FROM
posts WHERE (posts.id = 2) \e[0m\n"

Colorization may suck:


>> ActiveRecord::Base.colorize_logging = false
=> false
>> Post.find(1)
=> #<Post:0xb725ab68 @attributes={../..}>
>> @my_logger
=> "Post Load (0.000329)  SELECT * FROM posts WHERE (posts.id = 2) \n"

And voilà !
(Anyone has an easier idea?)

Share and Enjoy:
  • Twitter
  • Facebook
  • StumbleUpon
  • Google Bookmarks
  • LinkedIn
  • email
  • Slashdot
  • Digg
  • Netvibes
  • del.icio.us
  • HackerNews

No Comment.

Add Your Comment