Activerecord Query Generation

35 views
Skip to first unread message

Adam Thorsen

unread,
Aug 5, 2007, 11:41:47 AM8/5/07
to rubyonra...@googlegroups.com
Is there a way to just retrieve the sql that would be generated by an
activerecord call without actually executing the call?
--
Posted via http://www.ruby-forum.com/.

Bill Kocik

unread,
Aug 5, 2007, 1:54:39 PM8/5/07
to Ruby on Rails: Talk

On Aug 5, 11:41 am, Adam Thorsen <rails-mailing-l...@andreas-s.net>
wrote:


> Is there a way to just retrieve the sql that would be generated by an
> activerecord call without actually executing the call?

Umm, sort of, but it's almost certainly not what you were hoping for.

ActiveRecord generates the SQL it uses with a method called
construct_finder_sql(). That method is private, and it takes a hash of
options. The tricky thing is that the options can be put together by
any one of many execution paths depending upon how find() was called
and what was passed into it, and you sort of have to have a bit of
knowledge as to how ActiveRecord translates some of the symbols you
can pass to it.

For example, say you have a User model, and you want to know what
User.find(:first) translates to in SQL. In order to find out, you need
to know that when ActiveRecord sees :first, it translates this into an
entry in the options hash of ":limit => 1". So, if you want to know
what the SQL looks like for User.find(:first), what you really have to
do in your console (for demonstration purposes) is this:

User.send(:construct_finder_sql, {:limit => 1})

When I do that, I get back this:

=> "SELECT * FROM users LIMIT 1"

And there is the SQL ActiveRecord would have used to perform
User.find(:first). Using 'User.send(:construct_finder_sql)' sidesteps
the fact that that method is private. If I tried to call it directly,
I'd get an error.

One more example - how does AR execute User.find(1)? Well, I have to
know that the '1' argument causes AR to set {:conditions =>
'users.`id` = 1'} in it's options hash, and knowing this:

>> User.send(:construct_finder_sql, {:conditions => 'users.`id` = 1'})
=> "SELECT * FROM users WHERE (users.`id` = 1) "

So I think the answer to your question is, yes, there is a way -
unfortunately it's not a really straightforward one, and it requires a
good deal of detective work. By the time you figure out what to pass
into construct_finder_sql, you've practically answered the question of
what the SQL looks like anyways, so doing this may be of limited
usefulness.

Maybe someone else knows of an easier way, but I don't know what it
might be.

-Bill Kocik


Reply all
Reply to author
Forward
0 new messages