Add questions with mutiple answers to polls public interface

The `reload` method added to max_votes validation is needed because the
author gets here with some changes because of the around_action
`switch_locale`, which adds some changes to the current user record and
therefore, the lock method raises an exception when trying to lock it
requiring us to save or discard those record changes.
This commit is contained in:
decabeza
2022-09-02 16:41:17 +02:00
committed by Senén Rodero Rodríguez
parent 3da4112d94
commit 36e452437e
11 changed files with 121 additions and 5 deletions

View File

@@ -15,7 +15,8 @@
remote: true, remote: true,
title: t("poll_questions.show.vote_answer", answer: question_answer.title), title: t("poll_questions.show.vote_answer", answer: question_answer.title),
class: "button secondary hollow", class: "button secondary hollow",
"aria-pressed": false do %> "aria-pressed": false,
disabled: disable_answer?(question_answer) do %>
<%= question_answer.title %> <%= question_answer.title %>
<% end %> <% end %>
<% end %> <% end %>

View File

@@ -18,6 +18,10 @@ class Polls::Questions::AnswersComponent < ApplicationComponent
user_answers.find_by(answer: question_answer.title) user_answers.find_by(answer: question_answer.title)
end end
def disable_answer?(question_answer)
question.multiple? && user_answers.count == question.max_votes
end
private private
def user_answers def user_answers

View File

@@ -3,6 +3,12 @@
<%= question.title %> <%= question.title %>
</h3> </h3>
<% if question.votation_type.present? %>
<strong>
<%= t("poll_questions.description.#{question.vote_type}", maximum: question.max_votes) %>
</strong>
<% end %>
<div id="<%= dom_id(question) %>_answers" class="padding"> <div id="<%= dom_id(question) %>_answers" class="padding">
<%= render Polls::Questions::AnswersComponent.new(question) %> <%= render Polls::Questions::AnswersComponent.new(question) %>
</div> </div>

View File

@@ -5,9 +5,7 @@ class Polls::QuestionsController < ApplicationController
has_orders %w[most_voted newest oldest], only: :show has_orders %w[most_voted newest oldest], only: :show
def answer def answer
answer = @question.answers.find_or_initialize_by(author: current_user) answer = @question.find_or_initialize_user_answer(current_user, params[:answer])
answer.answer = params[:answer]
answer.save_and_record_voter_participation answer.save_and_record_voter_participation
respond_to do |format| respond_to do |format|
@@ -15,7 +13,7 @@ class Polls::QuestionsController < ApplicationController
redirect_to request.referer redirect_to request.referer
end end
format.js do format.js do
render :answer render :answers
end end
end end
end end

View File

@@ -10,4 +10,21 @@ module Questionable
def unique? def unique?
votation_type.nil? || votation_type.unique? votation_type.nil? || votation_type.unique?
end end
def find_or_initialize_user_answer(user, title)
answer = answers.find_or_initialize_by(find_by_attributes(user, title))
answer.answer = title
answer
end
private
def find_by_attributes(user, title)
case vote_type
when "unique", nil
{ author: user }
when "multiple"
{ author: user, answer: title }
end
end
end end

View File

@@ -38,6 +38,7 @@ class Poll::Answer < ApplicationRecord
def max_votes def max_votes
return if !question || question&.unique? || persisted? return if !question || question&.unique? || persisted?
author.reload
author.lock! author.lock!
if question.answers.by_author(author).count >= question.max_votes if question.answers.by_author(author).count >= question.max_votes

View File

@@ -636,6 +636,9 @@ en:
show: show:
vote_answer: "Vote %{answer}" vote_answer: "Vote %{answer}"
voted: "You have voted %{answer}" voted: "You have voted %{answer}"
description:
unique: "You can select a maximum of 1 answer."
multiple: "You can select a maximum of %{maximum} answers."
proposal_notifications: proposal_notifications:
new: new:
title: "Send notification" title: "Send notification"

View File

@@ -636,6 +636,9 @@ es:
show: show:
vote_answer: "Votar %{answer}" vote_answer: "Votar %{answer}"
voted: "Has votado %{answer}" voted: "Has votado %{answer}"
description:
unique: "Puedes seleccionar un máximo de 1 respuesta."
multiple: "Puedes seleccionar un máximo de %{maximum} respuestas."
proposal_notifications: proposal_notifications:
new: new:
title: "Enviar notificación" title: "Enviar notificación"

View File

@@ -33,6 +33,20 @@ describe Polls::Questions::AnswersComponent do
expect(page).to have_css "button[aria-pressed='true']", text: "Yes" expect(page).to have_css "button[aria-pressed='true']", text: "Yes"
end end
it "renders disabled buttons when max votes is reached" do
user = create(:user, :verified)
question = create(:poll_question_multiple, :abc, max_votes: 2, author: user)
create(:poll_answer, author: user, question: question, answer: "Answer A")
create(:poll_answer, author: user, question: question, answer: "Answer C")
sign_in(user)
render_inline Polls::Questions::AnswersComponent.new(question)
expect(page).to have_button "You have voted Answer A"
expect(page).to have_button "Vote Answer B", disabled: true
expect(page).to have_button "You have voted Answer C"
end
it "when user is not signed in, renders answers links pointing to user sign in path" do it "when user is not signed in, renders answers links pointing to user sign in path" do
render_inline Polls::Questions::AnswersComponent.new(question) render_inline Polls::Questions::AnswersComponent.new(question)

View File

@@ -0,0 +1,69 @@
require "rails_helper"
describe "Poll Votation Type" do
let(:author) { create(:user, :level_two) }
before do
login_as(author)
end
scenario "Unique answer" do
question = create(:poll_question_unique, :yes_no)
visit poll_path(question.poll)
expect(page).to have_content "You can select a maximum of 1 answer."
expect(page).to have_content(question.title)
expect(page).to have_button("Vote Yes")
expect(page).to have_button("Vote No")
within "#poll_question_#{question.id}_answers" do
click_button "Yes"
expect(page).to have_button("You have voted Yes")
expect(page).to have_button("Vote No")
click_button "No"
expect(page).to have_button("Vote Yes")
expect(page).to have_button("You have voted No")
end
end
scenario "Multiple answers" do
question = create(:poll_question_multiple, :abc, max_votes: 2)
visit poll_path(question.poll)
expect(page).to have_content "You can select a maximum of 2 answers."
expect(page).to have_content(question.title)
expect(page).to have_button("Vote Answer A")
expect(page).to have_button("Vote Answer B")
expect(page).to have_button("Vote Answer C")
within "#poll_question_#{question.id}_answers" do
click_button "Vote Answer A"
expect(page).to have_button("You have voted Answer A")
click_button "Vote Answer C"
expect(page).to have_button("You have voted Answer C")
expect(page).to have_button("Vote Answer B", disabled: true)
click_button "You have voted Answer A"
expect(page).to have_button("Vote Answer A")
expect(page).to have_button("Vote Answer B")
click_button "You have voted Answer C"
expect(page).to have_button("Vote Answer C")
click_button "Vote Answer B"
expect(page).to have_button("You have voted Answer B")
expect(page).to have_button("Vote Answer A")
expect(page).to have_button("Vote Answer C")
end
end
end