Add support for open-ended questions in admin section

Introduce a new "open" votation type for poll questions in the admin
interface. This type allows open answers provided by the user.
This commit is contained in:
taitus
2025-08-06 11:12:08 +02:00
parent eb10a3135b
commit 4e57e311dc
12 changed files with 56 additions and 5 deletions

View File

@@ -10,7 +10,8 @@ class Admin::VotationTypes::FieldsComponent < ApplicationComponent
def descriptions
{
unique: t("admin.polls.votation_type.unique_description"),
multiple: t("admin.polls.votation_type.multiple_description")
multiple: t("admin.polls.votation_type.multiple_description"),
open: t("admin.polls.votation_type.open_description")
}
end

View File

@@ -27,7 +27,7 @@ class Poll::Question < ApplicationRecord
accepts_nested_attributes_for :question_options, reject_if: :all_blank, allow_destroy: true
accepts_nested_attributes_for :votation_type
delegate :multiple?, :vote_type, to: :votation_type, allow_nil: true
delegate :multiple?, :open?, :vote_type, to: :votation_type, allow_nil: true
scope :sort_for_list, -> { order(Arel.sql("poll_questions.proposal_id IS NULL"), :created_at) }
scope :for_render, -> { includes(:author, :proposal) }

View File

@@ -3,7 +3,7 @@ class VotationType < ApplicationRecord
QUESTIONABLE_TYPES = %w[Poll::Question].freeze
enum :vote_type, { unique: 0, multiple: 1 }
enum :vote_type, { unique: 0, multiple: 1, open: 2 }
validates :questionable, presence: true
validates :questionable_type, inclusion: { in: ->(*) { QUESTIONABLE_TYPES }}

View File

@@ -534,6 +534,7 @@ en:
max_votes: Maximum number of votes
vote_type: Votation type
votation_type/vote_type:
open: Open-ended
unique: Unique answer
multiple: Multiple answers
cookies/vendor:

View File

@@ -1131,6 +1131,7 @@ en:
title: "Votation type"
unique_description: "It's only possible to answer one time to the question."
multiple_description: "Allows to choose multiple answers. It's possible to set the maximum number of answers."
open_description: "Open-ended question that allows users to provide a single answer in their own words."
questions:
index:
create: "Create question"

View File

@@ -534,6 +534,7 @@ es:
max_votes: Número máximo de votos
vote_type: Tipo de votación
votation_type/vote_type:
open: Respuesta abierta
unique: Respuesta única
multiple: Respuesta múltiple
cookies/vendor:

View File

@@ -1131,6 +1131,7 @@ es:
title: "Tipo de votación"
unique_description: "Solo se puede responder a la pregunta con una única respuesta."
multiple_description: "Permite elegir más de una respuesta. Se puede elegir el número máximo de respuestas."
open_description: "Pregunta abierta que permite al usuario dar una única respuesta con sus propias palabras."
questions:
index:
create: "Crear pregunta ciudadana"

View File

@@ -94,6 +94,12 @@ FactoryBot.define do
create(:votation_type_multiple, questionable: question, max_votes: evaluator.max_votes)
end
end
factory :poll_question_open do
after(:create) do |question|
create(:votation_type_open, questionable: question)
end
end
end
factory :poll_question_option, class: "Poll::Question::Option" do

View File

@@ -9,6 +9,10 @@ FactoryBot.define do
max_votes { 3 }
end
factory :votation_type_open do
vote_type { "open" }
end
questionable factory: :poll_question
end
end

View File

@@ -30,6 +30,13 @@ describe Poll::Answer do
expect(answer).not_to be_valid
end
it "is not valid without an answer when question is open-ended" do
answer.question = create(:poll_question_open)
answer.answer = nil
expect(answer).not_to be_valid
end
it "is not valid if there's already an answer to that question" do
author = create(:user)
question = create(:poll_question, :yes_no)

View File

@@ -1,7 +1,7 @@
require "rails_helper"
describe VotationType do
let(:vote_types) { %i[votation_type_unique votation_type_multiple] }
let(:vote_types) { %i[votation_type_unique votation_type_multiple votation_type_open] }
let(:votation_type) { build(vote_types.sample) }
it "is valid" do
@@ -27,6 +27,10 @@ describe VotationType do
expect(votation_type).to be_valid
votation_type.vote_type = "open"
expect(votation_type).to be_valid
votation_type.vote_type = "multiple"
expect(votation_type).not_to be_valid

View File

@@ -81,6 +81,8 @@ describe "Admin poll questions", :admin do
expect(page).to have_content "It's only possible to answer one time to the question."
expect(page).not_to have_content "Allows to choose multiple answers."
expect(page).not_to have_field "Maximum number of votes"
expect(page).not_to have_content "Open-ended question that allows users to provide " \
"a single answer in their own words."
click_button "Save"
@@ -94,6 +96,8 @@ describe "Admin poll questions", :admin do
expect(page).not_to have_content "It's only possible to answer one time to the question."
expect(page).to have_content "Allows to choose multiple answers."
expect(page).not_to have_content "Open-ended question that allows users to provide " \
"a single answer in their own words."
fill_in "Maximum number of votes", with: 6
click_button "Save"
@@ -101,6 +105,21 @@ describe "Admin poll questions", :admin do
expect(page).to have_content "Question with multiple answers"
expect(page).to have_content "Multiple answers"
end
scenario "Open-ended" do
fill_in "Question", with: "What do you want?"
select "Open-ended", from: "Votation type"
expect(page).not_to have_content "Allows to choose multiple answers."
expect(page).not_to have_field "Maximum number of votes"
expect(page).to have_content "Open-ended question that allows users to provide " \
"a single answer in their own words."
click_button "Save"
expect(page).to have_content "What do you want?"
expect(page).to have_content "Open-ended"
end
end
end
@@ -143,7 +162,7 @@ describe "Admin poll questions", :admin do
scenario "Update" do
poll = create(:poll, :future)
question = create(:poll_question, poll: poll)
question = create(:poll_question_open, poll: poll)
old_title = question.title
new_title = "Vegetables are great and everyone should have one"
@@ -154,6 +173,12 @@ describe "Admin poll questions", :admin do
end
expect(page).to have_link "Go back", href: admin_poll_path(poll)
expect(page).to have_select "Votation type", selected: "Open-ended"
expect(page).not_to have_content "Allows to choose multiple answers."
expect(page).not_to have_field "Maximum number of votes"
expect(page).to have_content "Open-ended question that allows users to provide " \
"a single answer in their own words."
fill_in "Question", with: new_title
click_button "Save"