Frage

I have two models: a Person has many Blurb(s).

In the controller I'm fetching all people and eagerly loading blurbs:

@people = Person.includes(:blurbs).all.sort { |x, y| y.updated_at <=> x.updated_at }

Then in the view I iterate through @people and display their individual blurb counts:

<% @people.each do |person| %>
  <%= person.blurbs.count %>
<% end %>

Rails' logger shows that all blurbs are indeed loaded:

Blurb Load (0.5ms) SELECT "blurbs".* FROM "blurbs" WHERE "blurbs"."person_id" IN \
(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, \
21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 32, 33, 27, 48, 49, 50)

But then it loads them all again when iterating instead of fetching from cache:

(0.4ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 27]]
(0.3ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 50]]
(0.3ms) SELECT COUNT(*) FROM "blurbs" WHERE "blurbs"."person_id" = $1  [["person_id", 49]]

What am I missing to use the eagerly loaded blurbs in order to cut down on the SQL queries?

War es hilfreich?

Lösung

Eager loading, as you have implemented above, will not cache counts. What you may be looking for to prevent those multiple “SELECT COUNT…” queries is a counter_cache.

You can implement it as follows:

class Blurb < ActiveRecord::Base
  belongs_to :person, counter_cache: true
end

…and then add a column to your Person table called blurbs_count

You can also specify a custom column if you so desire:

belongs_to :person, counter_cache: :count_of_blurbs

See: http://guides.rubyonrails.org/association_basics.html for more info.

Andere Tipps

I'd consider a counter_cache a bit OTT for this case. Try person.blurbs.size instead.

In short, size will conditionally call either length or count depending on previous queries.

From ActiveRecord source:

# File activerecord/lib/active_record/relation.rb, line 228
def size
  loaded? ? @records.length : count
end
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top