decidim-forms 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|