diff --git a/app/components/polls/questions/answers_component.html.erb b/app/components/polls/questions/answers_component.html.erb
index de84bcd7f..c73247ec2 100644
--- a/app/components/polls/questions/answers_component.html.erb
+++ b/app/components/polls/questions/answers_component.html.erb
@@ -15,7 +15,8 @@
remote: true,
title: t("poll_questions.show.vote_answer", answer: question_answer.title),
class: "button secondary hollow",
- "aria-pressed": false do %>
+ "aria-pressed": false,
+ disabled: disable_answer?(question_answer) do %>
<%= question_answer.title %>
<% end %>
<% end %>
diff --git a/app/components/polls/questions/answers_component.rb b/app/components/polls/questions/answers_component.rb
index b21459a97..0509d8fa7 100644
--- a/app/components/polls/questions/answers_component.rb
+++ b/app/components/polls/questions/answers_component.rb
@@ -18,6 +18,10 @@ class Polls::Questions::AnswersComponent < ApplicationComponent
user_answers.find_by(answer: question_answer.title)
end
+ def disable_answer?(question_answer)
+ question.multiple? && user_answers.count == question.max_votes
+ end
+
private
def user_answers
diff --git a/app/components/polls/questions/question_component.html.erb b/app/components/polls/questions/question_component.html.erb
index 5fd7eeb8b..3cd99a1b4 100644
--- a/app/components/polls/questions/question_component.html.erb
+++ b/app/components/polls/questions/question_component.html.erb
@@ -3,6 +3,12 @@
<%= question.title %>
+ <% if question.votation_type.present? %>
+
+ <%= t("poll_questions.description.#{question.vote_type}", maximum: question.max_votes) %>
+
+ <% end %>
+
<%= render Polls::Questions::AnswersComponent.new(question) %>
diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb
index 3731aa2f9..a21acc9bc 100644
--- a/app/controllers/polls/questions_controller.rb
+++ b/app/controllers/polls/questions_controller.rb
@@ -5,9 +5,7 @@ class Polls::QuestionsController < ApplicationController
has_orders %w[most_voted newest oldest], only: :show
def answer
- answer = @question.answers.find_or_initialize_by(author: current_user)
-
- answer.answer = params[:answer]
+ answer = @question.find_or_initialize_user_answer(current_user, params[:answer])
answer.save_and_record_voter_participation
respond_to do |format|
@@ -15,7 +13,7 @@ class Polls::QuestionsController < ApplicationController
redirect_to request.referer
end
format.js do
- render :answer
+ render :answers
end
end
end
diff --git a/app/models/concerns/questionable.rb b/app/models/concerns/questionable.rb
index f7b20b8f4..1d0606fc6 100644
--- a/app/models/concerns/questionable.rb
+++ b/app/models/concerns/questionable.rb
@@ -10,4 +10,21 @@ module Questionable
def unique?
votation_type.nil? || votation_type.unique?
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
diff --git a/app/models/poll/answer.rb b/app/models/poll/answer.rb
index 41d76e925..d9d86e9d6 100644
--- a/app/models/poll/answer.rb
+++ b/app/models/poll/answer.rb
@@ -38,6 +38,7 @@ class Poll::Answer < ApplicationRecord
def max_votes
return if !question || question&.unique? || persisted?
+ author.reload
author.lock!
if question.answers.by_author(author).count >= question.max_votes
diff --git a/app/views/polls/questions/answer.js.erb b/app/views/polls/questions/answers.js.erb
similarity index 100%
rename from app/views/polls/questions/answer.js.erb
rename to app/views/polls/questions/answers.js.erb
diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml
index 4a70c1a3e..afc277ef4 100644
--- a/config/locales/en/general.yml
+++ b/config/locales/en/general.yml
@@ -636,6 +636,9 @@ en:
show:
vote_answer: "Vote %{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:
new:
title: "Send notification"
diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml
index d731f4bd4..382b302e6 100644
--- a/config/locales/es/general.yml
+++ b/config/locales/es/general.yml
@@ -636,6 +636,9 @@ es:
show:
vote_answer: "Votar %{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:
new:
title: "Enviar notificación"
diff --git a/spec/components/polls/questions/answers_component_spec.rb b/spec/components/polls/questions/answers_component_spec.rb
index 0b05953c2..a5460b83e 100644
--- a/spec/components/polls/questions/answers_component_spec.rb
+++ b/spec/components/polls/questions/answers_component_spec.rb
@@ -33,6 +33,20 @@ describe Polls::Questions::AnswersComponent do
expect(page).to have_css "button[aria-pressed='true']", text: "Yes"
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
render_inline Polls::Questions::AnswersComponent.new(question)
diff --git a/spec/system/polls/votation_types_spec.rb b/spec/system/polls/votation_types_spec.rb
new file mode 100644
index 000000000..51efb7f2c
--- /dev/null
+++ b/spec/system/polls/votation_types_spec.rb
@@ -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