diff --git a/app/views/polls/questions/_answers.html.erb b/app/components/polls/questions/answers_component.html.erb
similarity index 92%
rename from app/views/polls/questions/_answers.html.erb
rename to app/components/polls/questions/answers_component.html.erb
index 08030bc0e..4e61ee767 100644
--- a/app/views/polls/questions/_answers.html.erb
+++ b/app/components/polls/questions/answers_component.html.erb
@@ -1,8 +1,8 @@
<% if can?(:answer, question) && !question.poll.voted_in_booth?(current_user) %>
<% question.question_answers.each do |answer| %>
- <% if @answers_by_question_id[question.id] == answer.title &&
- (!voted_before_sign_in(question) ||
+ <% if answers_by_question_id[question.id] == answer.title &&
+ (!voted_before_sign_in? ||
question.poll.voted_in_booth?(current_user)) %>
">
diff --git a/app/components/polls/questions/answers_component.rb b/app/components/polls/questions/answers_component.rb
new file mode 100644
index 000000000..1d64198a4
--- /dev/null
+++ b/app/components/polls/questions/answers_component.rb
@@ -0,0 +1,31 @@
+class Polls::Questions::AnswersComponent < ApplicationComponent
+ attr_reader :question
+ delegate :can?, :current_user, :user_signed_in?, to: :helpers
+
+ def initialize(question)
+ @question = question
+ end
+
+ def answers_by_question_id
+ if params[:answer]
+ { question.id => params[:answer] }
+ else
+ stored_answers_by_question_id
+ end
+ end
+
+ def voted_before_sign_in?
+ question.answers.where(author: current_user).any? do |vote|
+ vote.updated_at < current_user.current_sign_in_at
+ end
+ end
+
+ private
+
+ def stored_answers_by_question_id
+ poll_answers = ::Poll::Answer.by_question(question.poll.question_ids).by_author(current_user&.id)
+ poll_answers.each_with_object({}) do |answer, answers_by_question_id|
+ answers_by_question_id[answer.question_id] = answer.answer
+ end
+ end
+end
diff --git a/app/controllers/polls/questions_controller.rb b/app/controllers/polls/questions_controller.rb
index 51269cff1..3731aa2f9 100644
--- a/app/controllers/polls/questions_controller.rb
+++ b/app/controllers/polls/questions_controller.rb
@@ -10,8 +10,6 @@ class Polls::QuestionsController < ApplicationController
answer.answer = params[:answer]
answer.save_and_record_voter_participation
- @answers_by_question_id = { @question.id => params[:answer] }
-
respond_to do |format|
format.html do
redirect_to request.referer
diff --git a/app/controllers/polls_controller.rb b/app/controllers/polls_controller.rb
index f96298914..af2dc563a 100644
--- a/app/controllers/polls_controller.rb
+++ b/app/controllers/polls_controller.rb
@@ -21,13 +21,6 @@ class PollsController < ApplicationController
@questions = @poll.questions.for_render.sort_for_list
@poll_questions_answers = Poll::Question::Answer.where(question: @poll.questions)
.with_content.order(:given_order)
-
- @answers_by_question_id = {}
- poll_answers = ::Poll::Answer.by_question(@poll.question_ids).by_author(current_user&.id)
- poll_answers.each do |answer|
- @answers_by_question_id[answer.question_id] = answer.answer
- end
-
@commentable = @poll
@comment_tree = CommentTree.new(@commentable, params[:page], @current_order)
end
diff --git a/app/helpers/polls_helper.rb b/app/helpers/polls_helper.rb
index ee4ddb375..5a27d25db 100644
--- a/app/helpers/polls_helper.rb
+++ b/app/helpers/polls_helper.rb
@@ -12,10 +12,6 @@ module PollsHelper
booth.name + location
end
- def voted_before_sign_in(question)
- question.answers.where(author: current_user).any? { |vote| current_user.current_sign_in_at > vote.updated_at }
- end
-
def link_to_poll(text, poll)
if can?(:results, poll)
link_to text, results_poll_path(id: poll.slug || poll.id)
diff --git a/app/views/polls/questions/_question.html.erb b/app/views/polls/questions/_question.html.erb
index ade9c5910..5fd7eeb8b 100644
--- a/app/views/polls/questions/_question.html.erb
+++ b/app/views/polls/questions/_question.html.erb
@@ -4,6 +4,6 @@
- <%= render "polls/questions/answers", question: question %>
+ <%= render Polls::Questions::AnswersComponent.new(question) %>
diff --git a/app/views/polls/questions/answer.js.erb b/app/views/polls/questions/answer.js.erb
index f98441d0f..2c4380238 100644
--- a/app/views/polls/questions/answer.js.erb
+++ b/app/views/polls/questions/answer.js.erb
@@ -1 +1 @@
-$("#<%= dom_id(@question) %>_answers").html("<%= j render("polls/questions/answers", question: @question) %>");
+$("#<%= dom_id(@question) %>_answers").html("<%= j render Polls::Questions::AnswersComponent.new(@question) %>");
diff --git a/spec/components/polls/questions/answers_component_spec.rb b/spec/components/polls/questions/answers_component_spec.rb
new file mode 100644
index 000000000..e0a543a16
--- /dev/null
+++ b/spec/components/polls/questions/answers_component_spec.rb
@@ -0,0 +1,110 @@
+require "rails_helper"
+
+describe Polls::Questions::AnswersComponent do
+ include Rails.application.routes.url_helpers
+ let(:poll) { create(:poll) }
+ let(:question) { create(:poll_question, :yes_no, poll: poll) }
+
+ it "renders answers in given order" do
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect("Yes").to appear_before("No")
+ end
+
+ it "renders buttons to vote question answers" do
+ sign_in(create(:user, :verified))
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_button "Yes"
+ expect(page).to have_button "No"
+ end
+
+ it "renders a span instead of a button for existing user answers" do
+ user = create(:user, :verified)
+ allow(user).to receive(:current_sign_in_at).and_return(user.created_at)
+ create(:poll_answer, author: user, question: question, answer: "Yes")
+ sign_in(user)
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_selector "span", text: "Yes"
+ expect(page).not_to have_button "Yes"
+ expect(page).to have_button "No"
+ end
+
+ it "hides current answer and shows buttons in successive sessions" do
+ user = create(:user, :verified)
+ create(:poll_answer, author: user, question: question, answer: "Yes")
+ allow(user).to receive(:current_sign_in_at).and_return(Time.current)
+ sign_in(user)
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_button "Yes"
+ expect(page).to have_button "No"
+ 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)
+
+ expect(page).to have_link "Yes", href: new_user_session_path
+ expect(page).to have_link "No", href: new_user_session_path
+ end
+
+ it "when user is not verified, renders answers links pointing to user verification in path" do
+ sign_in(create(:user))
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_link "Yes", href: verification_path
+ expect(page).to have_link "No", href: verification_path
+ end
+
+ it "when user already voted in booth it renders disabled answers" do
+ user = create(:user, :level_two)
+ create(:poll_voter, :from_booth, poll: poll, user: user)
+ sign_in(user)
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_selector "span.disabled", text: "Yes"
+ expect(page).to have_selector "span.disabled", text: "No"
+ end
+
+ it "user cannot vote when poll expired it renders disabled answers" do
+ question = create(:poll_question, :yes_no, poll: create(:poll, :expired))
+ sign_in(create(:user, :level_two))
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_selector "span.disabled", text: "Yes"
+ expect(page).to have_selector "span.disabled", text: "No"
+ end
+
+ describe "geozone" do
+ let(:poll) { create(:poll, geozone_restricted: true) }
+ let(:geozone) { create(:geozone) }
+ let(:question) { create(:poll_question, :yes_no, poll: poll) }
+
+ it "when geozone which is not theirs it renders disabled answers" do
+ poll.geozones << geozone
+ sign_in(create(:user, :level_two))
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_selector "span.disabled", text: "Yes"
+ expect(page).to have_selector "span.disabled", text: "No"
+ end
+
+ it "reading a same-geozone poll it renders buttons to vote question answers" do
+ poll.geozones << geozone
+ sign_in(create(:user, :level_two, geozone: geozone))
+
+ render_inline Polls::Questions::AnswersComponent.new(question)
+
+ expect(page).to have_button "Yes"
+ expect(page).to have_button "No"
+ end
+ end
+end
diff --git a/spec/system/polls/polls_spec.rb b/spec/system/polls/polls_spec.rb
index c4ec85e99..220d832da 100644
--- a/spec/system/polls/polls_spec.rb
+++ b/spec/system/polls/polls_spec.rb
@@ -191,18 +191,6 @@ describe "Polls" do
expect("Second question").to appear_before("Third question")
end
- scenario "Question answers appear in the given order" do
- question = create(:poll_question, poll: poll)
- answer1 = create(:poll_question_answer, title: "First", question: question, given_order: 2)
- answer2 = create(:poll_question_answer, title: "Second", question: question, given_order: 1)
-
- visit poll_path(poll)
-
- within("div#poll_question_#{question.id}") do
- expect(answer2.title).to appear_before(answer1.title)
- end
- end
-
scenario "More info answers appear in the given order" do
question = create(:poll_question, poll: poll)
answer1 = create(:poll_question_answer, title: "First", question: question, given_order: 2)
@@ -248,8 +236,6 @@ describe "Polls" do
visit poll_path(poll)
expect(page).to have_content("You must sign in or sign up to participate")
- expect(page).to have_link("Yes", href: new_user_session_path)
- expect(page).to have_link("No", href: new_user_session_path)
end
scenario "Level 1 users" do
@@ -265,89 +251,19 @@ describe "Polls" do
visit poll_path(poll)
expect(page).to have_content("You must verify your account in order to answer")
-
- expect(page).to have_link("Yes", href: verification_path)
- expect(page).to have_link("No", href: verification_path)
end
scenario "Level 2 users in an expired poll" do
- expired_poll = create(:poll, :expired, geozone_restricted: true)
- expired_poll.geozones << geozone
-
- question = create(:poll_question, :yes_no, poll: expired_poll)
+ expired_poll = create(:poll, :expired)
+ create(:poll_question, :yes_no, poll: expired_poll)
login_as(create(:user, :level_two, geozone: geozone))
visit poll_path(expired_poll)
- within("#poll_question_#{question.id}_answers") do
- expect(page).to have_content("Yes")
- expect(page).to have_content("No")
- expect(page).not_to have_button "Yes"
- expect(page).not_to have_button "No"
- end
expect(page).to have_content("This poll has finished")
end
- scenario "Level 2 users in a poll with questions for a geozone which is not theirs" do
- poll.update!(geozone_restricted: true)
- poll.geozones << create(:geozone)
-
- question = create(:poll_question, :yes_no, poll: poll)
-
- login_as(create(:user, :level_two))
-
- visit poll_path(poll)
-
- within("#poll_question_#{question.id}_answers") do
- expect(page).to have_content("Yes")
- expect(page).to have_content("No")
- expect(page).not_to have_button "Yes"
- expect(page).not_to have_button "No"
- end
- end
-
- scenario "Level 2 users reading a same-geozone poll" do
- poll.update!(geozone_restricted: true)
- poll.geozones << geozone
-
- question = create(:poll_question, :yes_no, poll: poll)
-
- login_as(create(:user, :level_two, geozone: geozone))
- visit poll_path(poll)
-
- within("#poll_question_#{question.id}_answers") do
- expect(page).to have_button "Yes"
- expect(page).to have_button "No"
- end
- end
-
- scenario "Level 2 users reading a all-geozones poll" do
- question = create(:poll_question, :yes_no, poll: poll)
-
- login_as(create(:user, :level_two))
- visit poll_path(poll)
-
- within("#poll_question_#{question.id}_answers") do
- expect(page).to have_button "Yes"
- expect(page).to have_button "No"
- end
- end
-
- scenario "Level 2 users who have already answered" do
- question = create(:poll_question, :yes_no, poll: poll)
- user = create(:user, :level_two)
- create(:poll_answer, question: question, author: user, answer: "No")
-
- login_as user
- visit poll_path(poll)
-
- within("#poll_question_#{question.id}_answers") do
- expect(page).to have_button "Yes"
- expect(page).to have_button "No"
- end
- end
-
scenario "Level 2 users answering" do
poll.update!(geozone_restricted: true)
poll.geozones << geozone