Allow blank votes in polls via web
With the old interface, there wasn't a clear way to send a blank ballot. But now that we've got a form, there's an easy way: clicking on "Vote" while leaving the form blank.
This commit is contained in:
@@ -2,7 +2,11 @@
|
||||
<% if voted_in_booth? %>
|
||||
<%= callout(t("polls.show.already_voted_in_booth")) %>
|
||||
<% elsif voted_in_web? %>
|
||||
<%= callout(t("polls.show.already_voted_in_web")) %>
|
||||
<% if voted_blank? %>
|
||||
<%= callout(t("polls.show.already_voted_blank_in_web")) %>
|
||||
<% else %>
|
||||
<%= callout(t("polls.show.already_voted_in_web")) %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<% if current_user.nil? %>
|
||||
|
||||
@@ -16,6 +16,10 @@ class Polls::CalloutComponent < ApplicationComponent
|
||||
poll.voted_in_web?(current_user)
|
||||
end
|
||||
|
||||
def voted_blank?
|
||||
poll.answers.where(author: current_user).none?
|
||||
end
|
||||
|
||||
def callout(text, html_class: "warning")
|
||||
tag.div(text, class: "callout #{html_class}")
|
||||
end
|
||||
|
||||
@@ -26,7 +26,11 @@ class PollsController < ApplicationController
|
||||
@web_vote = Poll::WebVote.new(@poll, current_user)
|
||||
|
||||
if @web_vote.update(answer_params)
|
||||
redirect_to @poll, notice: t("flash.actions.create.poll_voter")
|
||||
if answer_params.blank?
|
||||
redirect_to @poll, notice: t("flash.actions.create.poll_voter_blank")
|
||||
else
|
||||
redirect_to @poll, notice: t("flash.actions.create.poll_voter")
|
||||
end
|
||||
else
|
||||
@comment_tree = CommentTree.new(@poll, params[:page], @current_order)
|
||||
render :show
|
||||
|
||||
@@ -23,6 +23,7 @@ class Poll < ApplicationRecord
|
||||
has_many :officer_assignments, through: :booth_assignments
|
||||
has_many :officers, through: :officer_assignments
|
||||
has_many :questions, inverse_of: :poll, dependent: :destroy
|
||||
has_many :answers, through: :questions
|
||||
has_many :comments, as: :commentable, inverse_of: :commentable
|
||||
has_many :ballot_sheets
|
||||
|
||||
|
||||
@@ -42,11 +42,11 @@ class Poll::Stats
|
||||
end
|
||||
|
||||
def total_web_valid
|
||||
voters.where(origin: "web").count - total_web_white
|
||||
voters.where(origin: "web", user_id: poll.answers.select(:author_id).distinct).count
|
||||
end
|
||||
|
||||
def total_web_white
|
||||
0
|
||||
voters.where(origin: "web").count - total_web_valid
|
||||
end
|
||||
|
||||
def total_web_null
|
||||
|
||||
@@ -14,10 +14,6 @@ class Poll::WebVote
|
||||
all_valid = true
|
||||
|
||||
user.with_lock do
|
||||
unless questions.any? { |question| params.dig(question.id.to_s, :option_id).present? }
|
||||
Poll::Voter.find_by(user: user, poll: poll, origin: "web")&.destroy!
|
||||
end
|
||||
|
||||
questions.each do |question|
|
||||
question.answers.where(author: user).destroy_all
|
||||
next unless params[question.id.to_s]
|
||||
|
||||
@@ -604,6 +604,7 @@ en:
|
||||
show:
|
||||
already_voted_in_booth: "You have already participated in a physical booth. You can not participate again."
|
||||
already_voted_in_web: "You have already participated in this poll. If you vote again it will be overwritten."
|
||||
already_voted_blank_in_web: "You have already participated in this poll by casting a blank vote. If you vote again it will be overwritten."
|
||||
back: Back to voting
|
||||
cant_answer_not_logged_in: "You must %{signin} or %{signup} to participate."
|
||||
comments_tab: Comments
|
||||
|
||||
@@ -11,6 +11,7 @@ en:
|
||||
poll_question_option_video: "Video created successfully"
|
||||
poll_question_option_image: "Image uploaded successfully"
|
||||
poll_voter: "Thank you for voting!"
|
||||
poll_voter_blank: "Thank you for voting! Your vote has been registered as a blank vote."
|
||||
proposal: "Proposal created successfully."
|
||||
proposal_notification: "Your message has been sent correctly."
|
||||
budget_investment: "Budget Investment created successfully."
|
||||
|
||||
@@ -604,6 +604,7 @@ es:
|
||||
show:
|
||||
already_voted_in_booth: "Ya has participado en esta votación en urnas presenciales, no puedes volver a participar."
|
||||
already_voted_in_web: "Ya has participado en esta votación. Si vuelves a votar se sobreescribirá tu resultado anterior."
|
||||
already_voted_blank_in_web: "Ya has participado en esta votación mediante un voto en blanco. Si vuelves a votar se sobreescribirá tu resultado anterior."
|
||||
back: Volver a votaciones
|
||||
cant_answer_not_logged_in: "Necesitas %{signin} o %{signup} para participar."
|
||||
comments_tab: Comentarios
|
||||
|
||||
@@ -11,6 +11,7 @@ es:
|
||||
poll_question_option_video: "Vídeo creado correctamente"
|
||||
poll_question_option_image: "Imagen cargada correctamente"
|
||||
poll_voter: "¡Gracias por votar!"
|
||||
poll_voter_blank: "¡Gracias por votar! Tu voto se ha contabilizado como en blanco."
|
||||
proposal: "Propuesta creada correctamente."
|
||||
proposal_notification: "Tu mensaje ha sido enviado correctamente."
|
||||
budget_investment: "Proyecto de gasto creado correctamente."
|
||||
|
||||
@@ -14,8 +14,6 @@ describe Poll::Stats do
|
||||
end
|
||||
|
||||
describe "total participants" do
|
||||
before { allow(stats).to receive(:total_web_white).and_return(1) }
|
||||
|
||||
it "supports every channel" do
|
||||
3.times { create(:poll_voter, :from_web, poll: poll) }
|
||||
create(:poll_recount, :from_booth, poll: poll,
|
||||
@@ -49,15 +47,29 @@ describe Poll::Stats do
|
||||
end
|
||||
|
||||
describe "#total_web_valid" do
|
||||
before { allow(stats).to receive(:total_web_white).and_return(1) }
|
||||
it "returns only votes containing answers" do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
|
||||
it "returns only valid votes" do
|
||||
3.times { create(:poll_voter, :from_web, poll: poll) }
|
||||
2.times do
|
||||
voter = create(:poll_voter, :from_web, poll: poll)
|
||||
create(:poll_answer, author: voter.user, question: question)
|
||||
end
|
||||
create(:poll_voter, :from_web, poll: poll)
|
||||
|
||||
expect(stats.total_web_valid).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#total_web_white" do
|
||||
it "returns voters with no answers" do
|
||||
question = create(:poll_question, :yes_no, poll: poll)
|
||||
3.times { create(:poll_voter, :from_web, poll: poll) }
|
||||
create(:poll_answer, author: poll.voters.last.user, question: question)
|
||||
|
||||
expect(stats.total_web_white).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#total_web_null" do
|
||||
it "returns 0" do
|
||||
expect(stats.total_web_null).to eq(0)
|
||||
@@ -93,8 +105,8 @@ describe Poll::Stats do
|
||||
|
||||
describe "valid percentage by channel" do
|
||||
it "is relative to the total amount of valid votes" do
|
||||
allow(stats).to receive(:total_web_valid).and_return(1)
|
||||
create(:poll_recount, :from_booth, poll: poll, total_amount: 2)
|
||||
create(:poll_voter, :from_web, poll: poll)
|
||||
|
||||
expect(stats.valid_percentage_web).to eq(33.333)
|
||||
expect(stats.valid_percentage_booth).to eq(66.667)
|
||||
@@ -123,7 +135,7 @@ describe Poll::Stats do
|
||||
|
||||
describe "#total_valid_votes" do
|
||||
it "counts valid votes from every channel" do
|
||||
2.times { create(:poll_voter, :from_web, poll: poll) }
|
||||
allow(stats).to receive(:total_web_valid).and_return(2)
|
||||
create(:poll_recount, :from_booth, poll: poll, total_amount: 3, white_amount: 10)
|
||||
create(:poll_recount, :from_booth, poll: poll, total_amount: 4, null_amount: 20)
|
||||
|
||||
@@ -150,10 +162,9 @@ describe Poll::Stats do
|
||||
end
|
||||
|
||||
describe "total percentage by type" do
|
||||
before { allow(stats).to receive(:total_web_white).and_return(1) }
|
||||
before { allow(stats).to receive_messages(total_web_white: 1, total_web_valid: 2) }
|
||||
|
||||
it "is relative to the total amount of votes" do
|
||||
3.times { create(:poll_voter, :from_web, poll: poll) }
|
||||
create(:poll_recount, :from_booth, poll: poll,
|
||||
total_amount: 8,
|
||||
white_amount: 5,
|
||||
|
||||
@@ -55,20 +55,21 @@ describe Poll::WebVote do
|
||||
expect(question.answers).to be_blank
|
||||
end
|
||||
|
||||
it "does not create voters or answers when leaving everything blank" do
|
||||
it "creates a voter but does not create answers when leaving everything blank" do
|
||||
web_vote.update({})
|
||||
|
||||
expect(poll.reload.voters.size).to eq 0
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
expect(question.reload.answers.size).to eq 0
|
||||
end
|
||||
|
||||
it "deletes existing answers and voter when no answers are given" do
|
||||
it "deletes existing answers but keeps voters when no answers are given" do
|
||||
create(:poll_answer, question: question, author: user, option: option_yes)
|
||||
create(:poll_voter, poll: poll, user: user)
|
||||
|
||||
web_vote.update({})
|
||||
|
||||
expect(poll.reload.voters.size).to eq 0
|
||||
expect(poll.reload.voters.size).to eq 1
|
||||
expect(poll.voters.first.user).to eq user
|
||||
expect(question.reload.answers.size).to eq 0
|
||||
end
|
||||
|
||||
|
||||
@@ -247,8 +247,9 @@ describe "Polls" do
|
||||
within_fieldset("Which ones are better?") { uncheck "Answer A" }
|
||||
click_button "Vote"
|
||||
|
||||
expect(page).to have_content "Thank you for voting!"
|
||||
expect(page).not_to have_content "You have already participated"
|
||||
expect(page).to have_content "Thank you for voting! Your vote has been registered as a blank vote."
|
||||
expect(page).to have_content "You have already participated in this poll by casting a blank vote. " \
|
||||
"If you vote again it will be overwritten."
|
||||
|
||||
within_fieldset("Which ones are better?") do
|
||||
expect(page).to have_field type: :checkbox, checked: false, count: 3
|
||||
|
||||
Reference in New Issue
Block a user