Rails scope overriding select
-
01-06-2021 - |
Question
I have a model with a has_many relationship, and a scope to determine whether or not it has any children, such as:
scope :with_nomination, :include => [:nomination], :conditions => "nominations.service_id IS NOT NULL"
Using this, I can do something like Service.with_nomination
and receive a list of all services with nomination children.
The problem is that when I do something like Service.select("id, firstName, lastName").with_nomination
ActiveRecord in essense does a SELECT * FROM services
which is very bad and does not utilize the indexes I so painstakingly set up.
How can I either rephrase my query or modify my scopes to work with the .select() command?
Solution
Turns out in the syntax I was using, a select is not possible, so it does a select * and any further selects are already overriden.
I re-wrote the scopes like so:
scope :no_nomination, joins("LEFT JOIN nominations ON nominations.service_id = services.id").where("nominations.service_id IS NULL")
# important distinction here, the left join allows you to find those records without children
scope :with_nomination, joins(:nomination).where("nominations.service_id IS NOT NULL")
Using this syntax allows me to do something like Service.select(:id,:user,:otherfield).with_nomination
OTHER TIPS
8 years later...
This is ugly, but you could also convert the resulting ActiveRecord::Relation
into to sql with to_sql
and run the command manually with ActiveRecord::Base.connection.execute
.
It might look like this:
query = Service.select("id, firstName, lastName").with_nomination.to_sql
records = ActiveRecord::Base.connection.execute(query)
records.first["firstName"] # => First Name
This doesn't eliminate the excess columns that the scope retrieves, and you have to access each field with string keys, but hey, at least you can still access them!