Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Anwendung im Rails-Umfragestil - Zeige alle Antworten auf Option

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.