I have Questions, which can be voted on. When I list each question on the question's index, I put the "yes" vote and "no" vote buttons alongside each one. I am trying to use Ajax to create votes and render a js view that updates the vote counts.
I'm observing this behavior: The votes are successfully created and saved. The first "yes" vote made on each question adjusts the count correctly for that question, but creating any "yes" votes after that will not update the count despite the vote objects being saved. The "no" buttons never update the label correctly. Randomly, clicking on a "No" button will increase that question's no_vote count to 80. If I refresh the page, all the counts update to the correct value as expected.
question.rb
class Question < ActiveRecord::Base
attr_accessible :body, :title, :pass_percentage
has_many :votes
has_many :yes_votes, class_name: 'Vote', conditions: { is_yes: true }
has_many :no_votes, class_name: 'Vote', conditions: { is_yes: false }
...
end
vote.rb
class Vote < ActiveRecord::Base
attr_accessible :is_yes, :question_id
belongs_to :question
validates :is_yes, inclusion: { in: [true, false]}
validates :question_id, presence: true
end
views/questions/index.html.erb
...
<%= will_paginate @questions %>
<ul class="questions">
<% @questions.each do |question| %>
<li>
<section class="question_<%= question.id %> clearfix">
<h2><%= link_to question.title, question_path(question) %></h2>
<p><%= truncate(question.body, length: 70) %></p>
<div class="vote-buttons">
<%= render partial: 'shared/yes_vote',
locals: { question: question } %>
<%= render partial: 'shared/no_vote',
locals: { question: question } %>
</div>
</section>
</li>
<% end %>
</ul>
...
_yes_vote.html.erb
<div class="vote-btn yes-vote-btn">
<%= form_for question.votes.build(is_yes: true), remote: true do |f| %>
<%= f.hidden_field :is_yes %>
<%= f.hidden_field :question_id %>
<%= f.submit "Yes", class: "btn btn-large btn-success" %>
<% end %>
<span class="yes-votes-count"><%= question.yes_votes.count %></p>
</div>
_no_vote.html.erb
<div class="vote-btn no-vote-btn">
<%= form_for question.votes.build(is_yes: false), remote: true do |f| %>
<%= f.hidden_field :is_yes %>
<%= f.hidden_field :question_id %>
<%= f.submit "No", class: "btn btn-large btn-danger" %>
<% end %>
<span class="no-votes-count"><%= question.no_votes.count %></span>
</div>
votes_controller.rb
class VotesController < ApplicationController
def new
@vote = Vote.new
end
def create
@vote = Vote.new(params[:vote])
@question = @vote.question
respond_to do |format|
if @vote.save
format.html { redirect_to :back }
format.js
else
format.html { redirect_to :back, flash: { error: "There was an error" } }
format.js
end
end
end
end
questions_controller.rb
class QuestionsController < ApplicationController
def index
@questions = Question.paginate(page: params[:page])
end
...
end
views/vote/create.js.erb
$(".question_<%= @question.id %> .yes-votes-count").html("<%= @question.yes_votes.count %>")
$(".question_<%= @question.id %> .no-votes-count").html("<%= @question.no_votes.count %>")
Server Log:
Started POST "/votes" for 127.0.0.1 at 2013-05-17 02:53:38 -0400
Processing by VotesController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"QD+7gj3G5r68B7cpxxW5ighB5M0Djluxx5XymnG4vog=", "vote"=>{"is_yes"=>"true", "question_id"=>"2"}, "commit"=>"Yes"}
Question Load (0.1ms) SELECT "questions".* FROM "questions" WHERE "questions"."id" = 2 LIMIT 1
(0.0ms) begin transaction
SQL (0.3ms) INSERT INTO "votes" ("created_at", "is_yes", "question_id", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?) [["created_at", Fri, 17 May 2013 06:53:38 UTC +00:00], ["is_yes", true], ["question_id", 2], ["updated_at", Fri, 17 May 2013 06:53:38 UTC +00:00], ["user_id", nil]]
(0.1ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."question_id" = 2 AND "votes"."is_yes" = 't'
(0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."question_id" = 2
Question Exists (0.0ms) SELECT 1 AS one FROM "questions" WHERE ("questions"."title" = 'Crust or no crust?' AND "questions"."id" != 2) LIMIT 1
(31.9ms) commit transaction
CACHE (0.0ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."question_id" = 2 AND "votes"."is_yes" = 't'
(0.1ms) SELECT COUNT(*) FROM "votes" WHERE "votes"."question_id" = 2 AND "votes"."is_yes" = 'f'
Rendered votes/create.js.erb (1.2ms)
Completed 200 OK in 39ms (Views: 2.3ms | ActiveRecord: 32.6ms)
Sorry for the large amount of code. I tried to make it as clear as possible.
Why is this not working? Is there a much better way to get write create.js.erb view?