sql >> Database >  >> RDS >> Mysql

Rails survey-stijl applicatie - Toon alle antwoorden op optie

Laten we beginnen met de relaties een beetje op te knappen:

class Question < ActiveRecord::Base
  has_many :options
  has_many :answers
  has_many :users, through: :answers
end

Er is technisch niets mis met has_many :answers, :through => :options maar aangezien er een directe relatie is via answers.question_id we hoeven de options niet te doorlopen tabel voor de relatie.

De telling weergeven

Als we het gewoon deden:

<td class="optionCell"><%= option.answers.count %></td>

Dit zou een vervelende n+1 . veroorzaken query om het aantal antwoorden voor elke optie op te halen. Dus wat we willen doen is een counter-cache maken die een telling opslaat in de optietabel.

Laten we beginnen met het maken van een migratie om de kolom toe te voegen:

rails g migration AddAnswerCounterCacheToOptions answers_count:integer
rake db:migrate

Vervolgens vertellen we ActiveRecord om de telling bij te werken wanneer we gekoppelde records maken, dit ziet er een beetje vreemd uit omdat de counter_cache: true aangifte staat op de belongs_to kant terwijl de kolom aan de andere kant is, maar dat is gewoon hoe AR werkt.

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 zit een klein scheurtje in. Aangezien we misschien al records hebben, moeten we ervoor zorgen dat ze de juiste tellers hebben. Je kunt dit vanaf de console doen, maar op de lange termijn is het een goed idee om maak een rake taak .

Option.find_each { |option| Option.reset_counters(option.id, :answers) }

Dit kan even duren, omdat elke optie moet worden opgehaald en de telling moet worden bijgewerkt.

Nu kunnen we de telling als volgt weergeven:

<% 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 is slim genoeg om onze counter-cachekolom te gebruiken, maar zal terugvallen op het opvragen van de telling, wat een goede zaak is voor tests.




  1. twee kolommen Draaien in Oracle SQL

  2. MySQL UITLEG:Index gebruiken versus indexvoorwaarde gebruiken

  3. SQLAlchemy - bulk invoegen negeren:dubbele invoer

  4. Proberen PostgreSQL-query te construeren om uit JSON een tekstwaarde in een object, in een array, in een object, in een array, in een object te extraheren