Vamos começar corrigindo um pouco as relações:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Não há nada tecnicamente errado com
has_many :answers, :through => :options
mas como existe uma relação direta através de answers.question_id
não precisamos passar pelas options
tabela para a relação. Exibindo a contagem
Se simplesmente fizéssemos:
<td class="optionCell"><%= option.answers.count %></td>
Isso criaria um desagradável
n+1
query para buscar a contagem das respostas para cada opção. Então, o que queremos fazer é criar um cache de contador
que armazena uma contagem na tabela de opções. Vamos começar criando uma migração para adicionar a coluna:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Em seguida, dizemos ao ActiveRecord para atualizar a contagem quando criamos registros associados, isso parece um pouco estranho, pois o
counter_cache: true
declaração está no belongs_to
lado enquanto a coluna está do outro, mas é assim que o AR funciona. 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
Há um pequeno problema aqui. Como já podemos ter registros, precisamos garantir que eles tenham contadores corretos. Você pode fazer isso no console, mas a longo prazo é uma boa ideia criar uma tarefa de rake .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
Isso pode demorar um pouco, pois precisa puxar cada Option e atualizar a contagem.
Agora podemos exibir a contagem assim:
<% 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
é inteligente o suficiente para usar nossa coluna de cache de contador, mas voltará a consultar a contagem, o que é bom para testes.