Beginnen wir damit, die Beziehungen ein wenig zu korrigieren:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Technisch gesehen ist nichts falsch an has_many :answers, :through => :options
sondern da es eine direkte Beziehung durch answers.question_id
gibt wir müssen nicht durch die options
gehen Tabelle für die Relation.
Zählung anzeigen
Wenn wir es einfach getan hätten:
<td class="optionCell"><%= option.answers.count %></td>
Dies würde ein unangenehmes n+1
erzeugen Abfrage, um die Anzahl der Antworten für jede Option abzurufen. Wir wollen also einen Counter-Cache erstellen
die eine Zählung in der Optionstabelle speichert.
Beginnen wir mit dem Erstellen einer Migration, um die Spalte hinzuzufügen:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Dann weisen wir ActiveRecord an, die Zählung zu aktualisieren, wenn wir verknüpfte Datensätze erstellen, dies sieht etwas seltsam aus, da counter_cache: true
-Deklaration befindet sich auf belongs_to
Seite, während die Spalte auf der anderen Seite ist, aber so funktioniert 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
Hier gibt es einen kleinen Haken. Da wir möglicherweise bereits Aufzeichnungen haben, müssen wir sicherstellen, dass sie über korrekte Zähler verfügen. Sie können dies von der Konsole aus tun, aber auf lange Sicht ist es eine gute Idee eine Rake-Aufgabe erstellen .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
Dies kann etwas Zeit in Anspruch nehmen, da jede Option abgerufen und die Anzahl aktualisiert werden muss.
Jetzt können wir die Bilanz wie folgt anzeigen:
<% 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
ist intelligent genug, um unsere Counter-Cache-Spalte zu verwenden, wird aber auf die Abfrage der Anzahl zurückgreifen, was für Tests eine gute Sache ist.