Mari kita mulai dengan memperbaiki hubungan sedikit:
class Question < ActiveRecord::Base
has_many :options
has_many :answers
has_many :users, through: :answers
end
Secara teknis tidak ada yang salah dengan has_many :answers, :through => :options
tetapi karena ada hubungan langsung melalui answers.question_id
kita tidak perlu melalui options
tabel untuk relasi.
Menampilkan hitungan
Jika kita melakukannya:
<td class="optionCell"><%= option.answers.count %></td>
Ini akan membuat n+1
nasty yang buruk query untuk mengambil jumlah jawaban untuk setiap opsi. Jadi yang ingin kita lakukan adalah membuat cache penghitung
yang menyimpan penghitungan pada tabel opsi.
Mari kita mulai dengan membuat migrasi untuk menambahkan kolom:
rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate
Kemudian kami memberi tahu ActiveRecord untuk memperbarui penghitungan saat kami membuat catatan terkait, ini terlihat agak aneh karena counter_cache: true
deklarasi ada di belongs_to
sisi sementara kolom di sisi lain tapi begitulah cara kerja 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
Ada sedikit halangan di sini. Karena kita mungkin sudah memiliki catatan, kita perlu memastikan bahwa mereka memiliki penghitung yang benar. Anda dapat melakukan ini dari konsol tetapi dalam jangka panjang sebaiknya membuat tugas menyapu .
Option.find_each { |option| Option.reset_counters(option.id, :answers) }
Ini mungkin memerlukan sedikit waktu karena perlu menarik setiap Opsi dan memperbarui hitungannya.
Sekarang kita dapat menampilkan penghitungan seperti ini:
<% 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
cukup pintar untuk menggunakan kolom cache penghitung kami, tetapi akan kembali menanyakan jumlah yang merupakan hal yang baik untuk pengujian.