Začněme tím, že trochu upravíme vztahy:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Na has_many :answers, :through => :options
není technicky nic špatného ale protože existuje přímý vztah prostřednictvím answers.question_id
nemusíme procházet options
tabulka pro vztah.
Zobrazení počtu
Kdybychom to prostě udělali:
<td class="optionCell"><%= option.answers.count %></td>
Vzniklo by ošklivé n+1
dotaz k načtení počtu odpovědí pro každou možnost. Chceme tedy vytvořit mezipaměť počítadel
který ukládá součet v tabulce možností.
Začněme vytvořením migrace pro přidání sloupce:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Poté řekneme ActiveRecord, aby aktualizoval záznam, když vytváříme související záznamy, vypadá to trochu divně, protože counter_cache: true
deklarace je na belongs_to
straně, zatímco sloupec je na druhé, ale přesně tak funguje AR.
class Option < ActiveRecord::Base
belongs_to :question
has_many :answers
end
class Answer < ActiveRecord::Base
belongs_to :user
belongs_to :question
belongs_to :option, counter_cache: true
end
Je zde malý zádrhel. Protože možná již máme záznamy, musíme se ujistit, že mají správná počítadla. Můžete to udělat z konzole, ale z dlouhodobého hlediska je dobrý nápad vytvořit úlohu rake .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
To může chvíli trvat, protože je třeba stáhnout každou možnost a aktualizovat počet.
Nyní můžeme zobrazit součet takto:
<% question.options.each do |option| %>
<tr class="backgroundColor1">
<td class="optionCell"><%= option.option_text %></td>
<td class="optionCell"><%= option.answers.size %></td>
</tr>
<% end %>
.size
je dostatečně chytrý na to, aby používal náš sloupec mezipaměti počítadel, ale vrátí se k dotazování na počet, což je dobrá věc pro testy.