Reputation: 6077
I am using meta_search to filter through a listing of cars. The car model is defined like this:
class Car < ActiveRecord::Base
has_many :images, :class_name => "CarImage"
......
end
I want to define a scope that can be used with meta_search, and to return only the cars that have at least an image. The only way I could make it work is to write a join inside the scope, but that seems to return duplicate car objects:
scope :with_images, joins(:images)
If I try to select only distinct values, like this:
scope :with_images, joins(:images).select('DISTINCT cars.*')
...I mess up the other methods that rely on my search results (such as avg and count aggregators, with group clauses).
While browsing through the Ruby on Rails Guides, I found a curious example, that might solve my problem, but can't get it to work and I don't really understand how it's done:
scope :published_and_commented, published.and(self.arel_table[:comments_count].gt(0))
If I use self.arel_table[:images_count]
then it says it's a nil object.
Throughout the application, we really have problems with searching and filtering using attributes from the association tables. We solved some problems by simply moving the attribute to the main cars
table, but this is kind of stupid, though it performs fast.
After giving it a thought, what would be viable in my opinion is, that the association would first get the list of all cars ids in the current search that have at least one image (this could be done with a simple INNER JOIN
and DISTINCT id
query) and then use the list of id-s to get the normal listing query, but with a WHERE id IN [id_1, id_2, id_3, ... , id_n]
clause.
Would that seem reasonable to you? And how would I do that? :D
Also, would be nice if I could do it without SQL, just with Arel or MetaWhere...
Upvotes: 0
Views: 466
Reputation: 115521
What you found in the Rals guides is the easiest way to proceed and even the fastest.
comments_count
is a counter_cache htat you can set on associations to get the number of children.
Implement it easily:
has_many :images, :class_name => "CarImage", :counter_cache => true
And then you'll be able to access the previous non existing images_count
.
Upvotes: 2