Question

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?

Était-ce utile?

La solution

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.

Autres conseils

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top