Commençons par corriger un peu les relations :
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Il n'y a rien de mal techniquement avec has_many :answers, :through => :options
mais comme il existe une relation directe via answers.question_id
nous n'avons pas besoin de passer par les options
table pour la relation.
Affichage du décompte
Si nous faisions simplement :
<td class="optionCell"><%= option.answers.count %></td>
Cela créerait un méchant n+1
query pour récupérer le nombre de réponses pour chaque option. Donc, ce que nous voulons faire, c'est créer un contre-cache
qui stocke un décompte sur la table des options.
Commençons par créer une migration pour ajouter la colonne :
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Ensuite, nous disons à ActiveRecord de mettre à jour le décompte lorsque nous créons des enregistrements associés, cela semble un peu étrange puisque le counter_cache: true
déclaration est sur le belongs_to
côté tandis que la colonne est de l'autre mais c'est comme ça que AR fonctionne.
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
Il y a un petit hic ici. Comme nous avons peut-être déjà des enregistrements, nous devons nous assurer qu'ils ont des compteurs corrects. Vous pouvez le faire à partir de la console, mais à long terme, c'est une bonne idée de créer une tâche de rake .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
Cela peut prendre un peu de temps car il doit extraire chaque option et mettre à jour le nombre.
Nous pouvons maintenant afficher le décompte comme suit :
<% 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
est assez intelligent pour utiliser notre colonne de cache de compteur, mais reviendra à interroger le nombre, ce qui est une bonne chose pour les tests.