Zacznijmy od poprawienia relacji:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Nie ma nic złego technicznie w has_many :answers, :through => :options
ale ponieważ istnieje bezpośrednia relacja poprzez answers.question_id
nie musimy przechodzić przez options
tabela dla relacji.
Wyświetlanie licznika
Jeśli po prostu zrobiliśmy:
<td class="optionCell"><%= option.answers.count %></td>
Stworzyłoby to paskudny n+1
zapytanie, aby pobrać liczbę odpowiedzi dla każdej opcji. Chcemy więc utworzyć pamięć podręczną liczników
który przechowuje zestawienie w tabeli opcji.
Zacznijmy od utworzenia migracji, aby dodać kolumnę:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Następnie mówimy ActiveRecord, aby aktualizował licznik, gdy tworzymy powiązane rekordy, wygląda to trochę dziwnie, ponieważ counter_cache: true
deklaracja znajduje się na belongs_to
z boku, podczas gdy kolumna jest po drugiej, ale tak właśnie działa 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
Tutaj jest mały szkopuł. Ponieważ możemy już mieć rekordy, musimy upewnić się, że mają prawidłowe liczniki. Możesz to zrobić z konsoli, ale na dłuższą metę dobrym pomysłem jest utwórz zadanie prowizji .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
Może to zająć trochę czasu, ponieważ trzeba pobrać każdą opcję i zaktualizować licznik.
Teraz możemy wyświetlić sumę w następujący sposób:
<% 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
jest wystarczająco sprytny, aby użyć naszej kolumny pamięci podręcznej liczników, ale wróci do zapytania o licznik, co jest dobre w przypadku testów.