Cristian
Cristian

Reputation: 6077

Using scope to only show items that have associated objects

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

Answers (1)

apneadiving
apneadiving

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.

See doc.

Upvotes: 2

Related Questions