Cominciamo col sistemare un po' le relazioni:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Non c'è niente di tecnicamente sbagliato in has_many :answers, :through => :options
ma poiché esiste una relazione diretta tramite answers.question_id
non abbiamo bisogno di passare attraverso le options
tabella per la relazione.
Visualizzazione del conteggio
Se lo facessimo semplicemente:
<td class="optionCell"><%= option.answers.count %></td>
Questo creerebbe un brutto n+1
query per recuperare il conteggio delle risposte per ciascuna opzione. Quindi quello che vogliamo fare è creare una cache del contatore
che memorizza un conteggio nella tabella delle opzioni.
Iniziamo creando una migrazione per aggiungere la colonna:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Quindi diciamo ad ActiveRecord di aggiornare il conteggio quando creiamo record associati, questo sembra un po' strano poiché counter_cache: true
la dichiarazione è su belongs_to
lato mentre la colonna è sull'altro, ma è proprio così che funziona 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
C'è un piccolo intoppo qui. Dal momento che potremmo già avere record, dobbiamo assicurarci che abbiano contatori corretti. Puoi farlo dalla console, ma a lungo termine è una buona idea crea un'attività di rake .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
L'operazione potrebbe richiedere un po' di tempo poiché è necessario estrarre ciascuna opzione e aggiornare il conteggio.
Ora possiamo visualizzare il conteggio in questo modo:
<% 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
è abbastanza intelligente da utilizzare la nostra colonna della cache del contatore, ma tornerà a interrogare il conteggio che è una buona cosa per i test.