Rails - eagerly loads the number of related posts, but not the posts themselves

I have a page that requires an age to render. Half the time (3 seconds) is spent calling .find, which has a bunch of associations loaded. All I really need is the number of related records in each case displayed in the table: I myself don't need the records themselves. Is there a way to just upload an invoice? Here's a simplified example:

@subjects = Subject.find(:all, :include => [:questions])

      

In my table, for each row (i.e., each object), I simply show the values โ€‹โ€‹of the topic fields and the number of related questions for each object. Can I optimize the above search call according to these requirements?

I was thinking about using a group box, but my full call involved several different associations with some second order associations, so I don't think the group will work.

@subjects = Subject.find(:all, :include => [{:questions => :tags}, {:quizzes => :tags}], :order => "subjects.name")

      

: tags in this case are second-order associations via tags. Here are my associations in case it is not clear what is happening.

Subject
  has_many :questions
  has_many :quizzes

Question
  belongs_to :subject
  has_many :taggings
  has_many :tags, :through => :taggings

Quiz
  belongs_to :subject
  has_many :taggings
  has_many :tags, :through => :taggings

      

Grateful for any advice - max

+2


a source to share


3 answers


I find it best used :counter_cache

in association belongs_to

.

class Subject < ActiveRecord::Base
  has_many :questions
end

class Question < ActiveRecord::Base
  belongs_to :subject, :counter_cache => true
end

      

To use counter_cache

, you also need to add a column questions_count

to the table subjects

.



From railsapi.com

:

: counter_cache
Caches the number of owned objects in the associated class using of increment_counter and decrement_counter. The cache counter is incremented when an object of this class is created and decremented when its destroyed [...]

+3


a source


You can use a cache counter for this purpose. I maintain a counter in the album model that keeps track of how many photos are associated with it. My process looks something like this (I believe I found this method on a blog somewhere, so I'm not taking responsibility for the source code):

In Model Pictures:

after_save :update_counter_caches
after_destroy :update_counter_caches

def update_counter_caches
  self.albums.each { |a| a.update_count } unless self.albums.empty?
end

      

In the album model:

def update_count
  update_attribute(:photographs_count, self.photographs.length)
end

      



The migration you need for albums:

class AddCounterCacheColumnToModels < ActiveRecord::Migration
  def self.up
    add_column :albums, :photographs_count, :integer, :default => 0
  end

  def self.down
    remove_column :albums, :photographs_count
  end
end

      

If I didn't understand your question, this should be a pretty neat way to achieve what you want. It works well in my current project. :)


EDIT: As a side note, the reason I am using this setting and not the default: counter_cache method is because I need to support multiple counters for multiple associations on the same model. As far as I know, you cannot achieve this with: counter_cache.

+1


a source


The fastest way I think is:

@subjects = Subject.count(:joins => :questions, :select => 'DISTINCT(questions.id)')

      

And I'm not sure about a more complex query (not tested):

@subjects = Subject.count(:joins => [{:questions => :tags}, {:quizzes => :tags}], :select => 'DISTINCT(tags.id)'

      

0


a source







All Articles