decidim-forms 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +65 -0
- data/Rakefile +3 -0
- data/app/assets/config/admin/decidim_forms_manifest.js +1 -0
- data/app/assets/config/decidim_forms_manifest.js +1 -0
- data/app/assets/images/decidim/surveys/icon.svg +19 -0
- data/app/assets/javascripts/decidim/forms/admin/auto_buttons_by_min_items.component.js.es6 +25 -0
- data/app/assets/javascripts/decidim/forms/admin/auto_select_options_by_total_items.component.js.es6 +23 -0
- data/app/assets/javascripts/decidim/forms/admin/forms.js.es6 +188 -0
- data/app/assets/javascripts/decidim/forms/autosortable_checkboxes.component.js.es6 +65 -0
- data/app/assets/javascripts/decidim/forms/forms.js.es6 +20 -0
- data/app/assets/javascripts/decidim/forms/option_attached_inputs.component.js.es6 +32 -0
- data/app/commands/decidim/forms/admin/update_questionnaire.rb +86 -0
- data/app/commands/decidim/forms/answer_questionnaire.rb +54 -0
- data/app/controllers/decidim/forms/admin/concerns/has_questionnaire.rb +95 -0
- data/app/controllers/decidim/forms/concerns/has_questionnaire.rb +84 -0
- data/app/forms/decidim/forms/admin/answer_option_form.rb +23 -0
- data/app/forms/decidim/forms/admin/question_form.rb +35 -0
- data/app/forms/decidim/forms/admin/questionnaire_form.rb +27 -0
- data/app/forms/decidim/forms/answer_choice_form.rb +15 -0
- data/app/forms/decidim/forms/answer_form.rb +69 -0
- data/app/forms/decidim/forms/questionnaire_form.rb +22 -0
- data/app/helpers/decidim/forms/admin/application_helper.rb +19 -0
- data/app/models/concerns/decidim/forms/has_questionnaire.rb +20 -0
- data/app/models/decidim/forms/answer.rb +45 -0
- data/app/models/decidim/forms/answer_choice.rb +15 -0
- data/app/models/decidim/forms/answer_option.rb +11 -0
- data/app/models/decidim/forms/application_record.rb +10 -0
- data/app/models/decidim/forms/question.rb +36 -0
- data/app/models/decidim/forms/questionnaire.rb +23 -0
- data/app/queries/decidim/forms/questionnaire_user_answers.rb +28 -0
- data/app/views/decidim/forms/admin/questionnaires/_answer_option.html.erb +44 -0
- data/app/views/decidim/forms/admin/questionnaires/_form.html.erb +51 -0
- data/app/views/decidim/forms/admin/questionnaires/_question.html.erb +115 -0
- data/app/views/decidim/forms/admin/questionnaires/edit.html.erb +7 -0
- data/app/views/decidim/forms/questionnaires/_answer.html.erb +94 -0
- data/app/views/decidim/forms/questionnaires/show.html.erb +84 -0
- data/config/locales/ca.yml +79 -0
- data/config/locales/de.yml +79 -0
- data/config/locales/en.yml +79 -0
- data/config/locales/es-PY.yml +79 -0
- data/config/locales/es.yml +79 -0
- data/config/locales/eu.yml +79 -0
- data/config/locales/fi-pl.yml +79 -0
- data/config/locales/fi.yml +79 -0
- data/config/locales/fr.yml +79 -0
- data/config/locales/gl.yml +79 -0
- data/config/locales/hu.yml +79 -0
- data/config/locales/id-ID.yml +1 -0
- data/config/locales/it.yml +79 -0
- data/config/locales/nl.yml +79 -0
- data/config/locales/pl.yml +79 -0
- data/config/locales/pt-BR.yml +79 -0
- data/config/locales/pt.yml +79 -0
- data/config/locales/ru.yml +1 -0
- data/config/locales/sv.yml +79 -0
- data/config/locales/tr-TR.yml +1 -0
- data/config/locales/uk.yml +1 -0
- data/db/migrate/20170511092231_create_decidim_forms_questionnaires.rb +15 -0
- data/db/migrate/20170515090916_create_decidim_forms_questions.rb +17 -0
- data/db/migrate/20170515144119_create_decidim_forms_answers.rb +15 -0
- data/db/migrate/20180405015012_create_decidim_forms_answer_options.rb +11 -0
- data/db/migrate/20180405015147_create_decidim_forms_answer_choices.rb +13 -0
- data/lib/decidim/forms.rb +13 -0
- data/lib/decidim/forms/admin.rb +9 -0
- data/lib/decidim/forms/admin_engine.rb +21 -0
- data/lib/decidim/forms/data_portability_user_answers_serializer.rb +37 -0
- data/lib/decidim/forms/engine.rb +14 -0
- data/lib/decidim/forms/test.rb +4 -0
- data/lib/decidim/forms/test/factories.rb +55 -0
- data/lib/decidim/forms/test/shared_examples/has_questionnaire.rb +524 -0
- data/lib/decidim/forms/test/shared_examples/manage_questionnaires.rb +626 -0
- data/lib/decidim/forms/user_answers_serializer.rb +29 -0
- data/lib/decidim/forms/version.rb +10 -0
- metadata +165 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Admin
|
6
|
+
# This command is executed when the user changes a Questionnaire from the admin
|
7
|
+
# panel.
|
8
|
+
class UpdateQuestionnaire < Rectify::Command
|
9
|
+
# Initializes a UpdateQuestionnaire Command.
|
10
|
+
#
|
11
|
+
# form - The form from which to get the data.
|
12
|
+
# questionnaire - The current instance of the questionnaire to be updated.
|
13
|
+
def initialize(form, questionnaire)
|
14
|
+
@form = form
|
15
|
+
@questionnaire = questionnaire
|
16
|
+
end
|
17
|
+
|
18
|
+
# Updates the questionnaire if valid.
|
19
|
+
#
|
20
|
+
# Broadcasts :ok if successful, :invalid otherwise.
|
21
|
+
def call
|
22
|
+
return broadcast(:invalid) if @form.invalid?
|
23
|
+
|
24
|
+
Decidim::Forms::Questionnaire.transaction do
|
25
|
+
update_questionnaire_questions if @questionnaire.questions_editable?
|
26
|
+
update_questionnaire
|
27
|
+
end
|
28
|
+
|
29
|
+
broadcast(:ok)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def update_questionnaire_questions
|
35
|
+
@form.questions.each do |form_question|
|
36
|
+
update_questionnaire_question(form_question)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def update_questionnaire_question(form_question)
|
41
|
+
question_attributes = {
|
42
|
+
body: form_question.body,
|
43
|
+
description: form_question.description,
|
44
|
+
position: form_question.position,
|
45
|
+
mandatory: form_question.mandatory,
|
46
|
+
question_type: form_question.question_type,
|
47
|
+
max_choices: form_question.max_choices
|
48
|
+
}
|
49
|
+
|
50
|
+
update_nested_model(form_question, question_attributes, @questionnaire.questions) do |question|
|
51
|
+
form_question.answer_options.each do |form_answer_option|
|
52
|
+
answer_option_attributes = {
|
53
|
+
body: form_answer_option.body,
|
54
|
+
free_text: form_answer_option.free_text
|
55
|
+
}
|
56
|
+
|
57
|
+
update_nested_model(form_answer_option, answer_option_attributes, question.answer_options)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def update_nested_model(form, attributes, parent_association)
|
63
|
+
record = parent_association.find_by(id: form.id) || parent_association.build(attributes)
|
64
|
+
|
65
|
+
yield record if block_given?
|
66
|
+
|
67
|
+
if record.persisted?
|
68
|
+
if form.deleted?
|
69
|
+
record.destroy!
|
70
|
+
else
|
71
|
+
record.update!(attributes)
|
72
|
+
end
|
73
|
+
else
|
74
|
+
record.save!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def update_questionnaire
|
79
|
+
@questionnaire.update!(title: @form.title,
|
80
|
+
description: @form.description,
|
81
|
+
tos: @form.tos)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
# This command is executed when the user answers a Questionnaire.
|
6
|
+
class AnswerQuestionnaire < Rectify::Command
|
7
|
+
# Initializes a AnswerQuestionnaire Command.
|
8
|
+
#
|
9
|
+
# form - The form from which to get the data.
|
10
|
+
# questionnaire - The current instance of the questionnaire to be answered.
|
11
|
+
def initialize(form, current_user, questionnaire)
|
12
|
+
@form = form
|
13
|
+
@current_user = current_user
|
14
|
+
@questionnaire = questionnaire
|
15
|
+
end
|
16
|
+
|
17
|
+
# Answers a questionnaire if it is valid
|
18
|
+
#
|
19
|
+
# Broadcasts :ok if successful, :invalid otherwise.
|
20
|
+
def call
|
21
|
+
return broadcast(:invalid) if @form.invalid?
|
22
|
+
|
23
|
+
answer_questionnaire
|
24
|
+
broadcast(:ok)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def answer_questionnaire
|
30
|
+
Answer.transaction do
|
31
|
+
@form.answers.each do |form_answer|
|
32
|
+
answer = Answer.new(
|
33
|
+
user: @current_user,
|
34
|
+
questionnaire: @questionnaire,
|
35
|
+
question: form_answer.question,
|
36
|
+
body: form_answer.body
|
37
|
+
)
|
38
|
+
|
39
|
+
form_answer.selected_choices.each do |choice|
|
40
|
+
answer.choices.build(
|
41
|
+
body: choice.body,
|
42
|
+
custom_body: choice.custom_body,
|
43
|
+
decidim_answer_option_id: choice.answer_option_id,
|
44
|
+
position: choice.position
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
answer.save!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Admin
|
6
|
+
module Concerns
|
7
|
+
# Questionnaires can be related to any class in Decidim, in order to
|
8
|
+
# manage the questionnaires for a given type, you should create a new
|
9
|
+
# controller and include this concern.
|
10
|
+
#
|
11
|
+
# The only requirement is to define a `questionnaire_for` method that
|
12
|
+
# returns an instance of the model that questionnaire belongs to.
|
13
|
+
module HasQuestionnaire
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
included do
|
17
|
+
helper Decidim::Forms::Admin::ApplicationHelper
|
18
|
+
helper_method :questionnaire_for, :questionnaire, :blank_question, :blank_answer_option, :question_types, :update_url
|
19
|
+
|
20
|
+
def edit
|
21
|
+
enforce_permission_to :update, :questionnaire, questionnaire: questionnaire
|
22
|
+
|
23
|
+
@form = form(Admin::QuestionnaireForm).from_model(questionnaire)
|
24
|
+
|
25
|
+
render template: "decidim/forms/admin/questionnaires/edit"
|
26
|
+
end
|
27
|
+
|
28
|
+
def update
|
29
|
+
enforce_permission_to :update, :questionnaire, questionnaire: questionnaire
|
30
|
+
|
31
|
+
params["published_at"] = Time.current if params.has_key? "save_and_publish"
|
32
|
+
@form = form(Admin::QuestionnaireForm).from_params(params)
|
33
|
+
|
34
|
+
Admin::UpdateQuestionnaire.call(@form, questionnaire) do
|
35
|
+
on(:ok) do
|
36
|
+
# i18n-tasks-use t("decidim.forms.admin.questionnaires.update.success")
|
37
|
+
flash[:notice] = I18n.t("update.success", scope: i18n_flashes_scope)
|
38
|
+
redirect_to after_update_url
|
39
|
+
end
|
40
|
+
|
41
|
+
on(:invalid) do
|
42
|
+
# i18n-tasks-use t("decidim.forms.admin.questionnaires.update.invalid")
|
43
|
+
flash.now[:alert] = I18n.t("update.invalid", scope: i18n_flashes_scope)
|
44
|
+
render template: "decidim/forms/admin/questionnaires/edit"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Public: The only method to be implemented at the controller. You need to
|
50
|
+
# return the object that will hold the questionnaire.
|
51
|
+
def questionnaire_for
|
52
|
+
raise "#{self.class.name} is expected to implement #questionnaire_for"
|
53
|
+
end
|
54
|
+
|
55
|
+
# You can implement this method in your controller to change the URL
|
56
|
+
# where the questionnaire will be submitted.
|
57
|
+
def update_url
|
58
|
+
url_for(questionnaire.questionnaire_for)
|
59
|
+
end
|
60
|
+
|
61
|
+
# You can implement this method in your controller to change the URL
|
62
|
+
# where the user will be redirected after updating the questionnaire
|
63
|
+
def after_update_url
|
64
|
+
url_for(questionnaire.questionnaire_for)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def i18n_flashes_scope
|
70
|
+
"decidim.forms.admin.questionnaires"
|
71
|
+
end
|
72
|
+
|
73
|
+
def questionnaire
|
74
|
+
@questionnaire ||= Questionnaire.find_by(questionnaire_for: questionnaire_for)
|
75
|
+
end
|
76
|
+
|
77
|
+
def blank_question
|
78
|
+
@blank_question ||= Admin::QuestionForm.new
|
79
|
+
end
|
80
|
+
|
81
|
+
def blank_answer_option
|
82
|
+
@blank_answer_option ||= Admin::AnswerOptionForm.new
|
83
|
+
end
|
84
|
+
|
85
|
+
def question_types
|
86
|
+
@question_types ||= Question::TYPES.map do |question_type|
|
87
|
+
[question_type, I18n.t("decidim.forms.question_types.#{question_type}")]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Concerns
|
6
|
+
# Questionnaires can be related to any class in Decidim, in order to
|
7
|
+
# manage the questionnaires for a given type, you should create a new
|
8
|
+
# controller and include this concern.
|
9
|
+
#
|
10
|
+
# The only requirement is to define a `questionnaire_for` method that
|
11
|
+
# returns an instance of the model that questionnaire belongs to.
|
12
|
+
module HasQuestionnaire
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
included do
|
16
|
+
include FormFactory
|
17
|
+
|
18
|
+
helper_method :questionnaire_for, :questionnaire, :allow_answers?, :update_url
|
19
|
+
|
20
|
+
def show
|
21
|
+
@form = form(Decidim::Forms::QuestionnaireForm).from_model(questionnaire)
|
22
|
+
render template: "decidim/forms/questionnaires/show"
|
23
|
+
end
|
24
|
+
|
25
|
+
def answer
|
26
|
+
enforce_permission_to :answer, :questionnaire
|
27
|
+
|
28
|
+
@form = form(Decidim::Forms::QuestionnaireForm).from_params(params)
|
29
|
+
|
30
|
+
Decidim::Forms::AnswerQuestionnaire.call(@form, current_user, questionnaire) do
|
31
|
+
on(:ok) do
|
32
|
+
# i18n-tasks-use t("decidim.forms.questionnaires.answer.success")
|
33
|
+
flash[:notice] = I18n.t("answer.success", scope: i18n_flashes_scope)
|
34
|
+
redirect_to after_answer_path
|
35
|
+
end
|
36
|
+
|
37
|
+
on(:invalid) do
|
38
|
+
# i18n-tasks-use t("decidim.forms.questionnaires.answer.invalid")
|
39
|
+
flash.now[:alert] = I18n.t("answer.invalid", scope: i18n_flashes_scope)
|
40
|
+
render template: "decidim/forms/questionnaires/show"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Public: Method to be implemented at the controller. You need to
|
46
|
+
# return true if the questionnaire can receive answers
|
47
|
+
def allow_answers?
|
48
|
+
raise "#{self.class.name} is expected to implement #allow_answers?"
|
49
|
+
end
|
50
|
+
|
51
|
+
# Public: Returns a String or Object that will be passed to `redirect_to` after
|
52
|
+
# answering the questionnaire. By default it redirects to the questionnaire_for.
|
53
|
+
#
|
54
|
+
# It can be redefined at controller level if you need to redirect elsewhere.
|
55
|
+
def after_answer_path
|
56
|
+
questionnaire_for
|
57
|
+
end
|
58
|
+
|
59
|
+
# You can implement this method in your controller to change the URL
|
60
|
+
# where the questionnaire will be submitted.
|
61
|
+
def update_url
|
62
|
+
url_for([questionnaire_for, action: :answer])
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Method to be implemented at the controller. You need to
|
66
|
+
# return the object that will hold the questionnaire.
|
67
|
+
def questionnaire_for
|
68
|
+
raise "#{self.class.name} is expected to implement #questionnaire_for"
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def i18n_flashes_scope
|
74
|
+
"decidim.forms.questionnaires"
|
75
|
+
end
|
76
|
+
|
77
|
+
def questionnaire
|
78
|
+
@questionnaire ||= Questionnaire.includes(questions: :answer_options).find_by(questionnaire_for: questionnaire_for)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Admin
|
6
|
+
# This class holds a Form to update answer options
|
7
|
+
class AnswerOptionForm < Decidim::Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
attribute :deleted, Boolean, default: false
|
11
|
+
attribute :free_text, Boolean
|
12
|
+
|
13
|
+
translatable_attribute :body, String
|
14
|
+
|
15
|
+
validates :body, translatable_presence: true, unless: :deleted
|
16
|
+
|
17
|
+
def to_param
|
18
|
+
id || "questionnaire-question-answer-option-id"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Admin
|
6
|
+
# This class holds a Form to update questionnaire questions from Decidim's admin panel.
|
7
|
+
class QuestionForm < Decidim::Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
attribute :position, Integer
|
11
|
+
attribute :mandatory, Boolean, default: false
|
12
|
+
attribute :question_type, String
|
13
|
+
attribute :answer_options, Array[AnswerOptionForm]
|
14
|
+
attribute :max_choices, Integer
|
15
|
+
attribute :deleted, Boolean, default: false
|
16
|
+
|
17
|
+
translatable_attribute :body, String
|
18
|
+
translatable_attribute :description, String
|
19
|
+
|
20
|
+
validates :position, numericality: { greater_than_or_equal_to: 0 }
|
21
|
+
validates :question_type, inclusion: { in: Decidim::Forms::Question::TYPES }
|
22
|
+
validates :max_choices, numericality: { only_integer: true, greater_than: 1, less_than_or_equal_to: ->(form) { form.number_of_options } }, allow_blank: true
|
23
|
+
validates :body, translatable_presence: true, unless: :deleted
|
24
|
+
|
25
|
+
def to_param
|
26
|
+
id || "questionnaire-question-id"
|
27
|
+
end
|
28
|
+
|
29
|
+
def number_of_options
|
30
|
+
answer_options.size
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
module Admin
|
6
|
+
# This class holds a Form to update questionnaires from Decidim's admin panel.
|
7
|
+
class QuestionnaireForm < Decidim::Form
|
8
|
+
include TranslatableAttributes
|
9
|
+
|
10
|
+
translatable_attribute :title, String
|
11
|
+
translatable_attribute :description, String
|
12
|
+
translatable_attribute :tos, String
|
13
|
+
|
14
|
+
attribute :published_at, Decidim::Attributes::TimeWithZone
|
15
|
+
attribute :questions, Array[QuestionForm]
|
16
|
+
|
17
|
+
validates :title, :tos, translatable_presence: true
|
18
|
+
|
19
|
+
def map_model(model)
|
20
|
+
self.questions = model.questions.map do |question|
|
21
|
+
QuestionForm.from_model(question)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
# This class holds a Form to save the chosen option for an answer
|
6
|
+
class AnswerChoiceForm < Decidim::Form
|
7
|
+
attribute :body, String
|
8
|
+
attribute :custom_body, String
|
9
|
+
attribute :position, Integer
|
10
|
+
attribute :answer_option_id, Integer
|
11
|
+
|
12
|
+
validates :answer_option_id, presence: true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Decidim
|
4
|
+
module Forms
|
5
|
+
# This class holds a Form to save the questionnaire answers from Decidim's public page
|
6
|
+
class AnswerForm < Decidim::Form
|
7
|
+
include Decidim::TranslationsHelper
|
8
|
+
|
9
|
+
attribute :question_id, String
|
10
|
+
attribute :body, String
|
11
|
+
attribute :choices, Array[AnswerChoiceForm]
|
12
|
+
|
13
|
+
validates :body, presence: true, if: :mandatory_body?
|
14
|
+
validates :selected_choices, presence: true, if: :mandatory_choices?
|
15
|
+
|
16
|
+
validate :max_choices, if: -> { question.max_choices }
|
17
|
+
validate :all_choices, if: -> { question.question_type == "sorting" }
|
18
|
+
|
19
|
+
delegate :mandatory_body?, :mandatory_choices?, to: :question
|
20
|
+
|
21
|
+
attr_writer :question
|
22
|
+
|
23
|
+
def question
|
24
|
+
@question ||= Decidim::Forms::Question.find(question_id)
|
25
|
+
end
|
26
|
+
|
27
|
+
def label(idx)
|
28
|
+
base = "#{idx + 1}. #{translated_attribute(question.body)}"
|
29
|
+
base += " #{mandatory_label}" if question.mandatory?
|
30
|
+
base += " (#{max_choices_label})" if question.max_choices
|
31
|
+
base
|
32
|
+
end
|
33
|
+
|
34
|
+
# Public: Map the correct fields.
|
35
|
+
#
|
36
|
+
# Returns nothing.
|
37
|
+
def map_model(model)
|
38
|
+
self.question_id = model.decidim_question_id
|
39
|
+
self.question = model.question
|
40
|
+
|
41
|
+
self.choices = model.choices.map do |choice|
|
42
|
+
AnswerChoiceForm.from_model(choice)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def selected_choices
|
47
|
+
choices.select(&:body)
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def max_choices
|
53
|
+
errors.add(:choices, :too_many) if selected_choices.size > question.max_choices
|
54
|
+
end
|
55
|
+
|
56
|
+
def all_choices
|
57
|
+
errors.add(:choices, :missing) if selected_choices.size != question.number_of_options
|
58
|
+
end
|
59
|
+
|
60
|
+
def mandatory_label
|
61
|
+
"*"
|
62
|
+
end
|
63
|
+
|
64
|
+
def max_choices_label
|
65
|
+
I18n.t("questionnaires.question.max_choices", scope: "decidim.forms", n: question.max_choices)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|