Bustikiller
Bustikiller

Reputation: 2508

ActiveRecord pluck to SQL

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.

Upvotes: 12

Views: 4877

Answers (2)

Pavan
Pavan

Reputation: 33542

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!

Upvotes: 11

Rudy Seidinger
Rudy Seidinger

Reputation: 1058

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

Upvotes: 3

Related Questions