Wednesday, September 6, 2017

ActiveRecord pluck to SQL

Leave a Comment

I know these two statements perform the same SQL:

Using select

User.select(:email) # SELECT  `users`.`email` FROM `users` 

And using pluck

User.all.pluck(:email) # SELECT `users`.`email` FROM `users` 

Now I need to get the SQL statement derived from each method. Given that the select method returns an ActiveRecord::Relation, I can call the to_sql method. However, I cannot figure out how to get the SQL statement derived from a pluck operation on an ActiveRecord::Relation object, given that the result is an array.

Please, take into account that this is a simplification of the problem. The number of attributes plucked can be arbitrarily high.

Any help would be appreciated.

2 Answers

Answers 1

You cannot chain to_sql with pluck as it doesn't return ActiveRecord::relation. If you try to do, it throws an exception like so

NoMethodError: undefined method `to_sql' for [[""]]:Array 

I cannot figure out how to get the SQL statement derived from a pluck operation on an ActiveRecord::Relation object, given that the result is an array.

Well, as @cschroed pointed out in the comments, they both(select and pluck) perform same SQL queries. The only difference is that pluck return an array instead of ActiveRecord::Relation. It doesn't matter how many attributes you are trying to pluck, the SQL statement will be same as select

Example:

User.select(:first_name,:email) #=> SELECT "users"."first_name", "users"."email" FROM "users" 

Same for pluck too

User.all.pluck(:first_name,:email) #=> SELECT "users"."first_name", "users"."email" FROM "users" 

So, you just need to take the SQL statement returned by the select and believe that it is the same for the pluck. That's it!

Answers 2

You could monkey-patch the ActiveRecord::LogSubscriber class and provide a singleton that would register any active record queries, even the ones that doesn't return ActiveRecord::Relation objects:

class QueriesRegister   include Singleton   def queries     @queries ||= []   end    def flush     @queries = []   end end  module ActiveRecord  class LogSubscriber < ActiveSupport::LogSubscriber    def sql(event)     QueriesRegister.instance.queries << event.payload[:sql]     "#{event.payload[:name]} (#{event.duration}) #{event.payload[:sql]}"       end  end end 

Run you query:

User.all.pluck(:email) 

Then, to retrieve the queries:

QueriesRegister.instance.queries 
If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment