fe 0.0.3
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/MIT-LICENSE +20 -0
- data/README.md +20 -0
- data/Rakefile +48 -0
- data/app/assets/images/fe/ajax-loader.gif +0 -0
- data/app/assets/images/fe/butgrad.png +0 -0
- data/app/assets/images/fe/icons/add.png +0 -0
- data/app/assets/images/fe/icons/application_form.png +0 -0
- data/app/assets/images/fe/icons/application_form_add.png +0 -0
- data/app/assets/images/fe/icons/arrow-move.png +0 -0
- data/app/assets/images/fe/icons/arrow_out.png +0 -0
- data/app/assets/images/fe/icons/asterisk_yellow.png +0 -0
- data/app/assets/images/fe/icons/book-open-list.png +0 -0
- data/app/assets/images/fe/icons/book_open.png +0 -0
- data/app/assets/images/fe/icons/briefcase.png +0 -0
- data/app/assets/images/fe/icons/calendar_view_day.png +0 -0
- data/app/assets/images/fe/icons/checkbox.png +0 -0
- data/app/assets/images/fe/icons/copy_paste.gif +0 -0
- data/app/assets/images/fe/icons/disk.png +0 -0
- data/app/assets/images/fe/icons/document--pencil.png +0 -0
- data/app/assets/images/fe/icons/document-copy.png +0 -0
- data/app/assets/images/fe/icons/map_magnify.png +0 -0
- data/app/assets/images/fe/icons/minus-button.png +0 -0
- data/app/assets/images/fe/icons/move.png +0 -0
- data/app/assets/images/fe/icons/page_error.png +0 -0
- data/app/assets/images/fe/icons/page_valid.png +0 -0
- data/app/assets/images/fe/icons/page_white.png +0 -0
- data/app/assets/images/fe/icons/page_white_add.png +0 -0
- data/app/assets/images/fe/icons/page_white_error.png +0 -0
- data/app/assets/images/fe/icons/paper-clip.png +0 -0
- data/app/assets/images/fe/icons/pencil-small.png +0 -0
- data/app/assets/images/fe/icons/pencil.png +0 -0
- data/app/assets/images/fe/icons/question-balloon.png +0 -0
- data/app/assets/images/fe/icons/radio.png +0 -0
- data/app/assets/images/fe/icons/star-small.png +0 -0
- data/app/assets/images/fe/icons/table.png +0 -0
- data/app/assets/images/fe/icons/text_align_left.png +0 -0
- data/app/assets/images/fe/icons/text_horizontalrule.png +0 -0
- data/app/assets/images/fe/icons/textfield.png +0 -0
- data/app/assets/images/fe/indent.png +0 -0
- data/app/assets/images/fe/overlay.png +0 -0
- data/app/assets/images/fe/selected_bg.jpg +0 -0
- data/app/assets/images/fe/status.gif +0 -0
- data/app/assets/images/fe/tooltip/black.png +0 -0
- data/app/assets/images/fe/tooltip/black_arrow.png +0 -0
- data/app/assets/images/fe/tooltip/black_arrow_big.png +0 -0
- data/app/assets/images/fe/tooltip/black_big.png +0 -0
- data/app/assets/images/fe/tooltip/white.png +0 -0
- data/app/assets/images/fe/tooltip/white_arrow.png +0 -0
- data/app/assets/images/fe/tooltip/white_arrow_big.png +0 -0
- data/app/assets/images/fe/tooltip/white_big.png +0 -0
- data/app/assets/images/fe/uploadify/cancel.png +0 -0
- data/app/assets/images/fe/uploadify/uploadify.swf +0 -0
- data/app/assets/javascripts/fe/admin.js +7 -0
- data/app/assets/javascripts/fe/jquery.metadata.js +122 -0
- data/app/assets/javascripts/fe/jquery.scrollTo-min.js +7 -0
- data/app/assets/javascripts/fe/jquery.uploadify.v2.1.0.js +258 -0
- data/app/assets/javascripts/fe/jquery.validate.pack.js +15 -0
- data/app/assets/javascripts/fe/qe.admin.js +115 -0
- data/app/assets/javascripts/fe/qe.common.js +57 -0
- data/app/assets/javascripts/fe/qe.public.js +331 -0
- data/app/assets/javascripts/fe/swfobject.js +4 -0
- data/app/assets/stylesheets/fe/qe.screen.css.scss.erb +552 -0
- data/app/assets/stylesheets/fe/reset.css +55 -0
- data/app/assets/stylesheets/fe/validation.css +91 -0
- data/app/controllers/fe/admin/elements_controller.rb +185 -0
- data/app/controllers/fe/admin/email_templates_controller.rb +61 -0
- data/app/controllers/fe/admin/question_pages_controller.rb +113 -0
- data/app/controllers/fe/admin/question_sheets_controller.rb +106 -0
- data/app/controllers/fe/answer_pages_controller.rb +3 -0
- data/app/controllers/fe/answer_sheets_controller.rb +3 -0
- data/app/controllers/fe/concerns/answer_pages_controller_concern.rb +80 -0
- data/app/controllers/fe/concerns/answer_sheets_controller_concern.rb +84 -0
- data/app/controllers/fe/reference_sheets_controller.rb +29 -0
- data/app/helpers/fe/answer_pages_helper.rb +19 -0
- data/app/helpers/fe/application_helper.rb +49 -0
- data/app/mailers/fe/notifier.rb +22 -0
- data/app/models/fe/answer.rb +13 -0
- data/app/models/fe/answer_pages_presenter.rb +13 -0
- data/app/models/fe/answer_sheet.rb +10 -0
- data/app/models/fe/answer_sheet_question_sheet.rb +7 -0
- data/app/models/fe/attachment_field.rb +7 -0
- data/app/models/fe/choice_field.rb +7 -0
- data/app/models/fe/concerns/answer_concern.rb +36 -0
- data/app/models/fe/concerns/answer_pages_presenter_concern.rb +99 -0
- data/app/models/fe/concerns/answer_sheet_concern.rb +61 -0
- data/app/models/fe/concerns/choice_field_concern.rb +131 -0
- data/app/models/fe/condition.rb +53 -0
- data/app/models/fe/date_field.rb +52 -0
- data/app/models/fe/element.rb +164 -0
- data/app/models/fe/email_template.rb +7 -0
- data/app/models/fe/option.rb +10 -0
- data/app/models/fe/option_group.rb +10 -0
- data/app/models/fe/page.rb +101 -0
- data/app/models/fe/page_element.rb +9 -0
- data/app/models/fe/page_link.rb +15 -0
- data/app/models/fe/paragraph.rb +10 -0
- data/app/models/fe/payment.rb +52 -0
- data/app/models/fe/payment_question.rb +22 -0
- data/app/models/fe/presenter.rb +23 -0
- data/app/models/fe/question.rb +256 -0
- data/app/models/fe/question_grid.rb +26 -0
- data/app/models/fe/question_grid_with_total.rb +11 -0
- data/app/models/fe/question_set.rb +82 -0
- data/app/models/fe/question_sheet.rb +73 -0
- data/app/models/fe/reference_question.rb +42 -0
- data/app/models/fe/reference_sheet.rb +149 -0
- data/app/models/fe/section.rb +12 -0
- data/app/models/fe/state_chooser.rb +10 -0
- data/app/models/fe/text_field.rb +29 -0
- data/app/views/fe/admin/elements/_errors.html.erb +1 -0
- data/app/views/fe/admin/elements/create.js.erb +11 -0
- data/app/views/fe/admin/elements/destroy.js.erb +4 -0
- data/app/views/fe/admin/elements/drop.js.erb +2 -0
- data/app/views/fe/admin/elements/duplicate.js.erb +2 -0
- data/app/views/fe/admin/elements/edit.js.erb +4 -0
- data/app/views/fe/admin/elements/error.js.erb +4 -0
- data/app/views/fe/admin/elements/new.js.erb +10 -0
- data/app/views/fe/admin/elements/reorder.js.erb +0 -0
- data/app/views/fe/admin/elements/update.js.erb +9 -0
- data/app/views/fe/admin/email_templates/_form.html.erb +8 -0
- data/app/views/fe/admin/email_templates/edit.html.erb +13 -0
- data/app/views/fe/admin/email_templates/index.html.erb +20 -0
- data/app/views/fe/admin/email_templates/new.html.erb +11 -0
- data/app/views/fe/admin/panels/_advanced_options.html.erb +16 -0
- data/app/views/fe/admin/panels/_common_fields.html.erb +24 -0
- data/app/views/fe/admin/panels/_condition.html.erb +6 -0
- data/app/views/fe/admin/panels/_insert.html.erb +39 -0
- data/app/views/fe/admin/panels/_nav_controls.html.erb +6 -0
- data/app/views/fe/admin/panels/_page.html.erb +3 -0
- data/app/views/fe/admin/panels/_pages_list.html.erb +16 -0
- data/app/views/fe/admin/panels/_prop_attachment_field.html.erb +2 -0
- data/app/views/fe/admin/panels/_prop_choice_field.html.erb +46 -0
- data/app/views/fe/admin/panels/_prop_date_field.html.erb +7 -0
- data/app/views/fe/admin/panels/_prop_element.html.erb +30 -0
- data/app/views/fe/admin/panels/_prop_page.html.erb +21 -0
- data/app/views/fe/admin/panels/_prop_paragraph.html.erb +32 -0
- data/app/views/fe/admin/panels/_prop_question_grid.html.erb +23 -0
- data/app/views/fe/admin/panels/_prop_question_grid_with_total.html.erb +14 -0
- data/app/views/fe/admin/panels/_prop_reference_question.html.erb +12 -0
- data/app/views/fe/admin/panels/_prop_section.html.erb +2 -0
- data/app/views/fe/admin/panels/_prop_sheet.html.erb +17 -0
- data/app/views/fe/admin/panels/_prop_text_field.html.erb +20 -0
- data/app/views/fe/admin/question_pages/_element.html.erb +18 -0
- data/app/views/fe/admin/question_pages/_element_show.html.erb +10 -0
- data/app/views/fe/admin/question_pages/_errors.html.erb +1 -0
- data/app/views/fe/admin/question_pages/_question_page.html.erb +13 -0
- data/app/views/fe/admin/question_pages/create.js.erb +11 -0
- data/app/views/fe/admin/question_pages/destroy.js.erb +5 -0
- data/app/views/fe/admin/question_pages/edit.js.erb +3 -0
- data/app/views/fe/admin/question_pages/error.js.erb +4 -0
- data/app/views/fe/admin/question_pages/show.js.erb +8 -0
- data/app/views/fe/admin/question_pages/show_panel.js.erb +3 -0
- data/app/views/fe/admin/question_pages/update.js.erb +2 -0
- data/app/views/fe/admin/question_sheets/_errors.html.erb +1 -0
- data/app/views/fe/admin/question_sheets/edit.js.erb +3 -0
- data/app/views/fe/admin/question_sheets/error.js.erb +5 -0
- data/app/views/fe/admin/question_sheets/index.html.erb +41 -0
- data/app/views/fe/admin/question_sheets/new.html.erb +15 -0
- data/app/views/fe/admin/question_sheets/show.html.erb +27 -0
- data/app/views/fe/admin/question_sheets/update.js.erb +2 -0
- data/app/views/fe/answer_pages/_answer_page.html.erb +56 -0
- data/app/views/fe/answer_pages/_element.html.erb +9 -0
- data/app/views/fe/answer_pages/update.js.erb +5 -0
- data/app/views/fe/answer_sheets/_answer_sheet.html.erb +24 -0
- data/app/views/fe/answer_sheets/_element.html.erb +54 -0
- data/app/views/fe/answer_sheets/_incomplete.html.erb +10 -0
- data/app/views/fe/answer_sheets/_page_link.html.erb +7 -0
- data/app/views/fe/answer_sheets/_pages_list.html.erb +11 -0
- data/app/views/fe/answer_sheets/_title.html.erb +1 -0
- data/app/views/fe/answer_sheets/edit.html.erb +60 -0
- data/app/views/fe/answer_sheets/incomplete.js.erb +5 -0
- data/app/views/fe/answer_sheets/index.html.erb +18 -0
- data/app/views/fe/answer_sheets/send_reference_invite.js.erb +8 -0
- data/app/views/fe/answer_sheets/show.html.erb +13 -0
- data/app/views/fe/help/builder.html +33 -0
- data/app/views/fe/help/question_grid.html +18 -0
- data/app/views/fe/questions/_acceptance.html.erb +13 -0
- data/app/views/fe/questions/_attachment_field.html.erb +42 -0
- data/app/views/fe/questions/_checkbox_field.html.erb +49 -0
- data/app/views/fe/questions/_country.html.erb +7 -0
- data/app/views/fe/questions/_date_field.html.erb +7 -0
- data/app/views/fe/questions/_date_field_mmyy.html.erb +9 -0
- data/app/views/fe/questions/_drop_down_field.html.erb +7 -0
- data/app/views/fe/questions/_paragraph.html.erb +1 -0
- data/app/views/fe/questions/_question_grid.html.erb +65 -0
- data/app/views/fe/questions/_question_grid_with_total.html.erb +57 -0
- data/app/views/fe/questions/_questions.html.erb +9 -0
- data/app/views/fe/questions/_radio_button_field.html.erb +41 -0
- data/app/views/fe/questions/_rating.html.erb +25 -0
- data/app/views/fe/questions/_reference_discipler.html.erb +1 -0
- data/app/views/fe/questions/_reference_friend.html.erb +1 -0
- data/app/views/fe/questions/_reference_parent.html.erb +1 -0
- data/app/views/fe/questions/_reference_peer.html.erb +1 -0
- data/app/views/fe/questions/_reference_question.html.erb +38 -0
- data/app/views/fe/questions/_reference_roommate.html.erb +1 -0
- data/app/views/fe/questions/_reference_spiritual.html.erb +1 -0
- data/app/views/fe/questions/_reference_staff.html.erb +1 -0
- data/app/views/fe/questions/_section.html.erb +1 -0
- data/app/views/fe/questions/_state_chooser.html.erb +7 -0
- data/app/views/fe/questions/_text_area_field.html.erb +6 -0
- data/app/views/fe/questions/_text_field.html.erb +8 -0
- data/app/views/fe/questions/_yes_no.html.erb +17 -0
- data/app/views/fe/questions/_yes_no_field.erb +17 -0
- data/app/views/fe/reference_sheets/not_found.html.erb +5 -0
- data/app/views/layouts/fe/application.html.erb +31 -0
- data/app/views/layouts/fe/qe.admin.html.erb +30 -0
- data/config/routes.rb +49 -0
- data/db/migrate/20131003041856_core.rb +91 -0
- data/db/migrate/20131003044250_create_reference_sheets.rb +23 -0
- data/db/migrate/20131003044436_add_element_and_answer_fields.rb +10 -0
- data/db/migrate/20131003044518_create_email_templates.rb +17 -0
- data/db/migrate/20131003044621_add_max_lengths.rb +8 -0
- data/db/migrate/20131003044714_create_join_table.rb +11 -0
- data/db/migrate/20131016162128_remove_question_id_from_element.rb +9 -0
- data/lib/fe.rb +22 -0
- data/lib/fe/engine.rb +19 -0
- data/lib/fe/version.rb +3 -0
- data/lib/generators/fe/install_generator.rb +132 -0
- data/lib/tasks/qe_tasks.rake +4 -0
- data/spec/controllers/fe/admin/elements_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/email_templates_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/question_pages_controller_spec.rb +4 -0
- data/spec/controllers/fe/admin/question_sheets_controller_spec.rb +4 -0
- data/spec/controllers/fe/answer_pages_controller_spec.rb +4 -0
- data/spec/controllers/fe/answer_sheets_controller_spec.rb +4 -0
- data/spec/controllers/fe/reference_sheets_controller_spec.rb +4 -0
- data/spec/factories/answer_sheets.rb +5 -0
- data/spec/factories/answers.rb +4 -0
- data/spec/factories/paragraphs.rb +4 -0
- data/spec/factories/question_sheet.rb +5 -0
- data/spec/factories/reference_questions.rb +4 -0
- data/spec/models/fe/answer_sheet_question_sheet_spec.rb +6 -0
- data/spec/models/fe/answer_sheet_spec.rb +8 -0
- data/spec/models/fe/answer_spec.rb +13 -0
- data/spec/models/fe/attachment_field_spec.rb +4 -0
- data/spec/models/fe/choice_field_spec.rb +5 -0
- data/spec/models/fe/condition_spec.rb +8 -0
- data/spec/models/fe/date_field_spec.rb +49 -0
- data/spec/models/fe/element_spec.rb +12 -0
- data/spec/models/fe/email_template_spec.rb +5 -0
- data/spec/models/fe/option_group_spec.rb +4 -0
- data/spec/models/fe/option_spec.rb +4 -0
- data/spec/models/fe/page_element_spec.rb +6 -0
- data/spec/models/fe/page_link_spec.rb +4 -0
- data/spec/models/fe/page_spec.rb +14 -0
- data/spec/models/fe/paragraph_spec.rb +17 -0
- data/spec/models/fe/question_grid_spec.rb +4 -0
- data/spec/models/fe/question_grid_with_total_spec.rb +4 -0
- data/spec/models/fe/question_set_spec.rb +4 -0
- data/spec/models/fe/question_sheet_spec.rb +8 -0
- data/spec/models/fe/question_spec.rb +20 -0
- data/spec/models/fe/reference_question_spec.rb +17 -0
- data/spec/models/fe/reference_sheet_spec.rb +11 -0
- data/spec/models/fe/section_spec.rb +4 -0
- data/spec/models/fe/state_chooser_spec.rb +4 -0
- data/spec/models/fe/text_field_spec.rb +17 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/support/database.txt +28 -0
- metadata +508 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Element represents a section, question or content element on the question sheet
|
|
2
|
+
module Fe
|
|
3
|
+
class Element < ActiveRecord::Base
|
|
4
|
+
self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
|
|
5
|
+
|
|
6
|
+
belongs_to :question_grid,
|
|
7
|
+
:class_name => "Fe::QuestionGrid",
|
|
8
|
+
:foreign_key => "question_grid_id"
|
|
9
|
+
|
|
10
|
+
belongs_to :choice_field,
|
|
11
|
+
:class_name => "Fe::ChoiceField",
|
|
12
|
+
:foreign_key => "conditional_id"
|
|
13
|
+
|
|
14
|
+
self.inheritance_column = :kind
|
|
15
|
+
|
|
16
|
+
has_many :page_elements, :dependent => :destroy
|
|
17
|
+
has_many :pages, :through => :page_elements
|
|
18
|
+
|
|
19
|
+
scope :active, -> { select("distinct(#{Fe::Element.table_name}.id), #{Fe::Element.table_name}.*").where(Fe::QuestionSheet.table_name + '.archived' => false).joins({:pages => :question_sheet}) }
|
|
20
|
+
|
|
21
|
+
validates_presence_of :kind
|
|
22
|
+
validates_presence_of :style
|
|
23
|
+
# validates_presence_of :label, :style, :on => :update
|
|
24
|
+
|
|
25
|
+
validates_length_of :kind, :maximum => 40, :allow_nil => true
|
|
26
|
+
validates_length_of :style, :maximum => 40, :allow_nil => true
|
|
27
|
+
# validates_length_of :label, :maximum => 255, :allow_nil => true
|
|
28
|
+
|
|
29
|
+
before_validation :set_defaults, :on => :create
|
|
30
|
+
|
|
31
|
+
# HUMANIZED_ATTRIBUTES = {
|
|
32
|
+
# :slug => "Variable"
|
|
33
|
+
# }changed.include?('address1')
|
|
34
|
+
#
|
|
35
|
+
# def self.human_attrib_name(attr)
|
|
36
|
+
# HUMANIZED_ATTRIBUTES[attr.to_sym] || super
|
|
37
|
+
# end
|
|
38
|
+
|
|
39
|
+
def has_response?(answer_sheet = nil)
|
|
40
|
+
false
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def limit(answer_sheet = nil)
|
|
44
|
+
if answer_sheet && object_name.present? && attribute_name.present?
|
|
45
|
+
begin
|
|
46
|
+
unless eval("answer_sheet." + self.object_name + ".nil?")
|
|
47
|
+
klass = eval("answer_sheet." + self.object_name + ".class")
|
|
48
|
+
column = klass.columns_hash[self.attribute_name]
|
|
49
|
+
column.limit
|
|
50
|
+
end
|
|
51
|
+
rescue
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def required?(answer_sheet = nil)
|
|
58
|
+
required == true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def position(page = nil)
|
|
62
|
+
if page
|
|
63
|
+
page_elements.where(:page_id => page.id).first.try(:position)
|
|
64
|
+
else
|
|
65
|
+
self[:position]
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def set_position(position, page = nil)
|
|
70
|
+
if page
|
|
71
|
+
pe = page_elements.where(:page_id => page.id).first
|
|
72
|
+
pe.update_attribute(:position, position) if pe
|
|
73
|
+
else
|
|
74
|
+
self[:position] = position
|
|
75
|
+
end
|
|
76
|
+
position
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def page_id(page = nil)
|
|
80
|
+
if page
|
|
81
|
+
page.id
|
|
82
|
+
else
|
|
83
|
+
pages.first.id
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def question?
|
|
88
|
+
self.kind_of?(Question)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# by default the partial for an element matches the class name (override as necessary)
|
|
93
|
+
def ptemplate
|
|
94
|
+
self.class.to_s.underscore
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# copy an item and all it's children
|
|
98
|
+
def duplicate(page, parent = nil)
|
|
99
|
+
new_element = self.class.new(self.attributes.except('id', 'created_at', 'updated_at'))
|
|
100
|
+
case parent.class.to_s
|
|
101
|
+
when Fe::ChoiceField
|
|
102
|
+
new_element.conditional_id = parent.id
|
|
103
|
+
when Fe::QuestionGrid, Fe::QuestionGridWithTotal
|
|
104
|
+
new_element.question_grid_id = parent.id
|
|
105
|
+
end
|
|
106
|
+
new_element.save(:validate => false)
|
|
107
|
+
Fe::PageElement.create(:element => new_element, :page => page) unless parent
|
|
108
|
+
|
|
109
|
+
# duplicate children
|
|
110
|
+
if respond_to?(:elements) && elements.present?
|
|
111
|
+
elements.each {|e| e.duplicate(page, new_element)}
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
new_element
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# include nested elements
|
|
118
|
+
def all_elements
|
|
119
|
+
if respond_to?(:elements)
|
|
120
|
+
(elements + elements.collect(&:all_elements)).flatten
|
|
121
|
+
else
|
|
122
|
+
[]
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def reuseable?
|
|
127
|
+
(self.is_a?(Question) || self.is_a?(Fe::QuestionGrid) || self.is_a?(Fe::QuestionGridWithTotal))
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def self.max_label_length
|
|
131
|
+
@@max_label_length ||= Fe::Element.columns.find{ |c| c.name == "label" }.limit
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
protected
|
|
135
|
+
def set_defaults
|
|
136
|
+
if self.content.blank?
|
|
137
|
+
case self.class.to_s
|
|
138
|
+
when "Fe::ChoiceField" then self.content ||= "Choice One\nChoice Two\nChoice Three"
|
|
139
|
+
when "Fe::Paragraph" then self.content ||="Lorem ipsum..."
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
if self.style.blank?
|
|
144
|
+
case self.class.to_s
|
|
145
|
+
when 'Fe::TextField' then self.style ||= 'essay'
|
|
146
|
+
when "Fe::DateField" then self.style ||= "date"
|
|
147
|
+
when "Fe::FileField" then self.style ||= "file"
|
|
148
|
+
when "Fe::Paragraph" then self.style ||= "paragraph"
|
|
149
|
+
when "Fe::Section" then self.style ||= "section"
|
|
150
|
+
when "Fe::ChoiceField" then self.style = "checkbox"
|
|
151
|
+
when "Fe::QuestionGrid" then self.style ||= "grid"
|
|
152
|
+
when "Fe::QuestionGridWithTotal" then self.style ||= "grid_with_total"
|
|
153
|
+
when "Fe::SchoolPicker" then self.style ||= "school_picker"
|
|
154
|
+
when "Fe::ProjectPreference" then self.style ||= "project_preference"
|
|
155
|
+
when "Fe::StateChooser" then self.style ||= "state_chooser"
|
|
156
|
+
when "Fe::ReferenceQuestion" then self.style ||= "peer"
|
|
157
|
+
else
|
|
158
|
+
self.style ||= self.class.to_s.underscore
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
164
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require 'acts_as_list'
|
|
2
|
+
module Fe
|
|
3
|
+
class Page < ActiveRecord::Base
|
|
4
|
+
self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
|
|
5
|
+
|
|
6
|
+
belongs_to :question_sheet
|
|
7
|
+
|
|
8
|
+
has_many :page_elements, -> { order(:position) },
|
|
9
|
+
:dependent => :destroy
|
|
10
|
+
|
|
11
|
+
has_many :elements, -> { order(Fe::PageElement.table_name + '.position') },
|
|
12
|
+
:through => :page_elements
|
|
13
|
+
|
|
14
|
+
has_many :question_grid_with_totals, -> { where("kind = 'Fe::QuestionGridWithTotal'") },
|
|
15
|
+
:through => :page_elements,
|
|
16
|
+
:source => :element
|
|
17
|
+
|
|
18
|
+
has_many :questions, -> { where("kind NOT IN('Fe::Paragraph', 'Fe::Section', 'Fe::QuestionGrid', 'Fe::QuestionGridWithTotal')") },
|
|
19
|
+
:through => :page_elements,
|
|
20
|
+
:source => :element
|
|
21
|
+
|
|
22
|
+
has_many :question_grids, -> { where("kind = 'Fe::QuestionGrid'") },
|
|
23
|
+
:through => :page_elements,
|
|
24
|
+
:source => :element
|
|
25
|
+
|
|
26
|
+
# has_many :conditions, :class_name => "Condition", :foreign_key => "toggle_page_id", # conditions associated with page as a whole
|
|
27
|
+
# :conditions => 'toggle_id is NULL', :dependent => :nullify
|
|
28
|
+
|
|
29
|
+
acts_as_list :column => :number, :scope => :question_sheet_id
|
|
30
|
+
|
|
31
|
+
scope :visible, -> { where(:hidden => false) }
|
|
32
|
+
|
|
33
|
+
# callbacks
|
|
34
|
+
before_validation :set_default_label, :on => :create # Page x
|
|
35
|
+
|
|
36
|
+
# validation
|
|
37
|
+
validates_presence_of :label, :number
|
|
38
|
+
validates_length_of :label, :maximum => 100, :allow_nil => true
|
|
39
|
+
|
|
40
|
+
# validates_uniqueness_of :number, :scope => :question_sheet_id
|
|
41
|
+
|
|
42
|
+
validates_numericality_of :number, :only_integer => true
|
|
43
|
+
|
|
44
|
+
# a page is disabled if there is a condition, and that condition evaluates to false
|
|
45
|
+
# could set multiple conditions to influence this question, in which case all must be met
|
|
46
|
+
# def active?
|
|
47
|
+
# # find first condition that doesn't pass (nil if all pass)
|
|
48
|
+
# self.conditions.detect { |c| !c.evaluate? }.nil? # true if all pass
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# def question?
|
|
52
|
+
# false
|
|
53
|
+
# end
|
|
54
|
+
|
|
55
|
+
def questions_before_position(position)
|
|
56
|
+
self.elements.where(["#{Fe::PageElement.table_name}.position < ?", position])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Include nested elements
|
|
60
|
+
def all_elements
|
|
61
|
+
(elements + elements.collect(&:all_elements)).flatten
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def copy_to(question_sheet)
|
|
65
|
+
new_page = Fe::Page.new(self.attributes)
|
|
66
|
+
new_page.question_sheet_id = question_sheet.id
|
|
67
|
+
new_page.save(:validate => false)
|
|
68
|
+
self.elements.each do |element|
|
|
69
|
+
if !question_sheet.archived? && element.reuseable?
|
|
70
|
+
Fe::PageElement.create(:element => element, :page => new_page)
|
|
71
|
+
else
|
|
72
|
+
element.duplicate(new_page)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def complete?(answer_sheet)
|
|
78
|
+
all_elements.all? {|e| !e.required?(answer_sheet) || e.has_response?(answer_sheet)}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def started?(answer_sheet)
|
|
82
|
+
all_elements.any? {|e| e.has_response?(answer_sheet)}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def has_questions?
|
|
86
|
+
all_elements.any? {|e| e.is_a?(Question)}
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# next unused label with "Page" prefix
|
|
92
|
+
def set_default_label
|
|
93
|
+
self.label = Fe.next_label("Page", Fe::Page.untitled_labels(self.question_sheet)) if self.label.blank?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def self.untitled_labels(sheet)
|
|
97
|
+
sheet ? sheet.pages.where("label like 'Page %'").map {|p| p.label} : []
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# represents a link to a page for the page_list sidebar or next page links
|
|
2
|
+
module Fe
|
|
3
|
+
class PageLink
|
|
4
|
+
attr_accessor :dom_id, :label, :load_path, :page
|
|
5
|
+
attr_accessor :save_path # to save current page
|
|
6
|
+
|
|
7
|
+
def initialize(label, load_path, dom_id, page)
|
|
8
|
+
@label = label
|
|
9
|
+
@load_path = load_path
|
|
10
|
+
@dom_id = dom_id
|
|
11
|
+
@page = page
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Paragraph
|
|
2
|
+
# - Represents a block of content
|
|
3
|
+
#
|
|
4
|
+
# :kind - 'Fe::Paragraph' for single table inheritance (STI)
|
|
5
|
+
# :content - instructions, agreements, etc. to display
|
|
6
|
+
module Fe
|
|
7
|
+
class Paragraph < Element
|
|
8
|
+
validates_presence_of :content, :on => :update
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Fe
|
|
2
|
+
class Payment < ActiveRecord::Base
|
|
3
|
+
self.table_name = self.table_name.sub('fe_', Fe.table_name_prefix)
|
|
4
|
+
|
|
5
|
+
attr_accessor :first_name, :last_name, :address, :city, :state, :zip, :card_number, :payment_type,
|
|
6
|
+
:expiration_month, :expiration_year, :security_code, :staff_first, :staff_last, :card_type
|
|
7
|
+
|
|
8
|
+
scope :non_denied, -> { where("(status <> 'Denied' AND status <> 'Errored') OR status is null") }
|
|
9
|
+
|
|
10
|
+
belongs_to :answer_sheet, class_name: Fe.answer_sheet_class
|
|
11
|
+
|
|
12
|
+
after_save :check_answer_sheet_complete
|
|
13
|
+
|
|
14
|
+
def validate
|
|
15
|
+
if credit?
|
|
16
|
+
errors.add_on_empty([:first_name, :last_name, :address, :city, :state, :zip, :card_number,
|
|
17
|
+
:expiration_month, :expiration_year, :security_code])
|
|
18
|
+
errors.add(:card_number, "is invalid.") if get_card_type.nil?
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def check_answer_sheet_complete
|
|
23
|
+
if self.approved?
|
|
24
|
+
self.answer_sheet.complete
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def credit?
|
|
29
|
+
self.payment_type == 'Credit Card'
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def staff?
|
|
33
|
+
self.payment_type == 'Staff'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def approved?
|
|
37
|
+
self.status == 'Approved'
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def approve!
|
|
41
|
+
self.status = 'Approved'
|
|
42
|
+
self.save!
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def get_card_type
|
|
46
|
+
card = ActiveMerchant::Billing::CreditCard.new(:number => card_number)
|
|
47
|
+
card.valid?
|
|
48
|
+
card.type
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Fe
|
|
2
|
+
class PaymentQuestion < Question
|
|
3
|
+
|
|
4
|
+
def response(answer_sheet=nil)
|
|
5
|
+
return Payment.new unless answer_sheet
|
|
6
|
+
answer_sheet.payments || [Payment.new(:answer_sheetlication_id => answer_sheet.id) ]
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def display_response(answer_sheet=nil)
|
|
10
|
+
response(answer_sheet).to_s
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def has_response?(answer_sheet = nil)
|
|
14
|
+
if answer_sheet
|
|
15
|
+
answer_sheet.payments.length > 0
|
|
16
|
+
else
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# based on http://blog.caboo.se/articles/2007/8/23/simple-presenters
|
|
2
|
+
module Fe
|
|
3
|
+
class Presenter
|
|
4
|
+
include ActionView::Helpers::TagHelper # link_to
|
|
5
|
+
# include ActionView::Helpers::UrlHelper # url_for
|
|
6
|
+
include ActionController::UrlFor # named routes
|
|
7
|
+
include ActionController::RecordIdentifier # dom_id
|
|
8
|
+
include Rails.application.routes.url_helpers
|
|
9
|
+
attr_accessor :controller # so we can be lazy
|
|
10
|
+
|
|
11
|
+
def initialize(controller)
|
|
12
|
+
@controller = controller
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def request
|
|
16
|
+
@controller.request
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def env
|
|
20
|
+
@controller.env
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
# Question
|
|
2
|
+
# - An individual question element
|
|
3
|
+
# - children: TextField, ChoiceField, DateField, FileField
|
|
4
|
+
|
|
5
|
+
# :kind - 'TextField', 'ChoiceField', 'DateField' for single table inheritance (STI)
|
|
6
|
+
# :label - label for the question, such as "First name"
|
|
7
|
+
# :style - essay|phone|email|numeric|currency|simple, selectbox|radio, checkbox, my|mdy
|
|
8
|
+
# :required - is this question itself required or optional?
|
|
9
|
+
# :content - choices (one per line) for choice field
|
|
10
|
+
|
|
11
|
+
module Fe
|
|
12
|
+
class Question < Element
|
|
13
|
+
include ActionController::RecordIdentifier # dom_id
|
|
14
|
+
has_many :conditions,
|
|
15
|
+
:class_name => "Condition",
|
|
16
|
+
:foreign_key => "toggle_id",
|
|
17
|
+
:dependent => :nullify
|
|
18
|
+
|
|
19
|
+
has_many :dependents,
|
|
20
|
+
:class_name => "Condition",
|
|
21
|
+
:foreign_key => "trigger_id",
|
|
22
|
+
:dependent => :nullify
|
|
23
|
+
|
|
24
|
+
has_many :sheet_answers,
|
|
25
|
+
:class_name => "Answer",
|
|
26
|
+
:foreign_key => "question_id",
|
|
27
|
+
:dependent => :destroy
|
|
28
|
+
|
|
29
|
+
belongs_to :related_question_sheet,
|
|
30
|
+
:class_name => "QuestionSheet",
|
|
31
|
+
:foreign_key => "related_question_sheet_id"
|
|
32
|
+
|
|
33
|
+
# validates_inclusion_of :required, :in => [false, true]
|
|
34
|
+
|
|
35
|
+
validates_format_of :slug, :with => /\A[a-z_][a-z0-9_]*\z/,
|
|
36
|
+
:allow_nil => true, :if => Proc.new { |q| !q.slug.blank? },
|
|
37
|
+
:message => 'may only contain lowercase letters, digits and underscores; and cannot begin with a digit.' # enforcing lowercase because javascript is case-sensitive
|
|
38
|
+
validates_length_of :slug, :in => 4..36,
|
|
39
|
+
:allow_nil => true, :if => Proc.new { |q| !q.slug.blank? }
|
|
40
|
+
validates_uniqueness_of :slug,
|
|
41
|
+
:allow_nil => true, :if => Proc.new { |q| !q.slug.blank? },
|
|
42
|
+
:message => 'must be unique.'
|
|
43
|
+
|
|
44
|
+
# a question has one response per AnswerSheet (that is, an instance of a user filling out the question)
|
|
45
|
+
# generally the response is a single answer
|
|
46
|
+
# however, "Choose Many" (checkbox) questions have multiple answers in a single response
|
|
47
|
+
|
|
48
|
+
attr_accessor :answers
|
|
49
|
+
|
|
50
|
+
# @answers = nil # one or more answers in response to this question
|
|
51
|
+
# @mark_for_destroy = nil # when something is unchecked, there are less answers to the question than before
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# a question is disabled if there is a condition, and that condition evaluates to false
|
|
55
|
+
# could set multiple conditions to influence this question, in which case all must be met
|
|
56
|
+
# def active?
|
|
57
|
+
# # find first condition that doesn't pass (nil if all pass)
|
|
58
|
+
# self.conditions.find(:all).find { |c| !c.evaluate? }.nil? # true if all pass
|
|
59
|
+
# end
|
|
60
|
+
|
|
61
|
+
# def conditions_attributes=(new_conditions)
|
|
62
|
+
# conditions.collect(&:destroy)
|
|
63
|
+
# conditions.reload
|
|
64
|
+
# (0..(new_conditions.length - 1)).each do |i|
|
|
65
|
+
# i = i.to_s
|
|
66
|
+
# expression = new_conditions[i]["expression"]
|
|
67
|
+
# trigger_id = new_conditions[i]["trigger_id"].to_i
|
|
68
|
+
# unless expression.blank? || !page.questions.collect(&:id).include?(trigger_id) || conditions.collect(&:trigger_id).include?(trigger_id)
|
|
69
|
+
# conditions.create(:question_sheet_id => question_sheet_id, :trigger_id => trigger_id,
|
|
70
|
+
# :expression => expression, :toggle_page_id => page_id,
|
|
71
|
+
# :toggle_id => self.id)
|
|
72
|
+
# end
|
|
73
|
+
# end
|
|
74
|
+
# end
|
|
75
|
+
|
|
76
|
+
# element view provides the element label with required indicator
|
|
77
|
+
def default_label?
|
|
78
|
+
true
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def locked?(params, answer_sheet, presenter)
|
|
82
|
+
return true unless params['controller'] == 'answer_pages' && params['action'] == 'edit'
|
|
83
|
+
if self.object_name == 'person.current_address' && ['address1','address2','city','zip','email','state','country'].include?(self.attribute_name)
|
|
84
|
+
# Billing Address
|
|
85
|
+
return false
|
|
86
|
+
elsif self.object_name == 'person.emergency_address' && ['address1','address2','city','zip','email','state','country','contactName','homePhone','workPhone'].include?(self.attribute_name)
|
|
87
|
+
# Emergency Contact
|
|
88
|
+
return false
|
|
89
|
+
elsif self.label == 'Relationship To You' || self.style == "country" || (self.style == "email" && self.label == "Confirm Email")
|
|
90
|
+
# Relationship & Country & Email Address
|
|
91
|
+
return false
|
|
92
|
+
else
|
|
93
|
+
return answer_sheet.frozen? && !presenter.reference?
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# css class names for javascript-based validation
|
|
98
|
+
def validation_class(answer_sheet = nil)
|
|
99
|
+
if required?(answer_sheet)
|
|
100
|
+
' required '
|
|
101
|
+
else
|
|
102
|
+
''
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# just in case something slips through client-side validation?
|
|
107
|
+
# def valid_response?
|
|
108
|
+
# if self.required? && !self.has_response? then
|
|
109
|
+
# false
|
|
110
|
+
# else
|
|
111
|
+
# # other validations
|
|
112
|
+
# true
|
|
113
|
+
# end
|
|
114
|
+
# end
|
|
115
|
+
|
|
116
|
+
# just in case something slips through client-side validation?
|
|
117
|
+
# def valid_response_for_answer_sheet?(answers)
|
|
118
|
+
# return true if !self.required?
|
|
119
|
+
# answer = answers.detect {|a| a.question_id == self.id}
|
|
120
|
+
# return answer && answer.value.present?
|
|
121
|
+
# # raise answer.inspect
|
|
122
|
+
# end
|
|
123
|
+
|
|
124
|
+
# shortcut to return first answer
|
|
125
|
+
def response(answer_sheet)
|
|
126
|
+
responses(answer_sheet).first.to_s
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def display_response(answer_sheet)
|
|
130
|
+
r = responses(answer_sheet)
|
|
131
|
+
if r.blank?
|
|
132
|
+
""
|
|
133
|
+
else
|
|
134
|
+
r.join(", ")
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def responses(answer_sheet)
|
|
139
|
+
return [] unless answer_sheet
|
|
140
|
+
|
|
141
|
+
# try to find answer from external object
|
|
142
|
+
if !object_name.blank? and !attribute_name.blank?
|
|
143
|
+
obj = object_name == 'answer_sheet' ? answer_sheet : eval("answer_sheet." + object_name)
|
|
144
|
+
if obj.nil? or eval("obj." + attribute_name + ".nil?")
|
|
145
|
+
[]
|
|
146
|
+
else
|
|
147
|
+
[eval("obj." + attribute_name)]
|
|
148
|
+
end
|
|
149
|
+
else
|
|
150
|
+
#answer_sheet.answers_by_question[id] || []
|
|
151
|
+
Fe::Answer.where(:answer_sheet_id => answer_sheet.id, :question_id => self.id)
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# set answers from posted response
|
|
156
|
+
def set_response(values, answer_sheet)
|
|
157
|
+
values = Array.wrap(values)
|
|
158
|
+
if !object_name.blank? and !attribute_name.blank?
|
|
159
|
+
# if eval("answer_sheet." + object_name).present?
|
|
160
|
+
object = object_name == 'answer_sheet' ? answer_sheet : eval("answer_sheet." + object_name)
|
|
161
|
+
unless object.present?
|
|
162
|
+
if object_name.include?('.')
|
|
163
|
+
objects = object_name.split('.')
|
|
164
|
+
object = eval("answer_sheet." + objects[0..-2].join('.') + ".create_" + objects.last)
|
|
165
|
+
eval("answer_sheet." + objects[0..-2].join('.')).reload
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
unless responses(answer_sheet) == values
|
|
169
|
+
value = values.first
|
|
170
|
+
if self.is_a?(Fe::DateField) && value.present?
|
|
171
|
+
begin
|
|
172
|
+
value = Date.strptime(value, (I18n.t 'date.formats.default'))
|
|
173
|
+
rescue
|
|
174
|
+
raise "invalid date - " + value.inspect
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
object.update_attribute(attribute_name, value)
|
|
178
|
+
end
|
|
179
|
+
# else
|
|
180
|
+
# raise object_name.inspect + ' == ' + attribute_name.inspect
|
|
181
|
+
# end
|
|
182
|
+
else
|
|
183
|
+
@answers ||= []
|
|
184
|
+
@mark_for_destroy ||= []
|
|
185
|
+
# go through existing answers (in reverse order, as we delete)
|
|
186
|
+
(@answers.length - 1).downto(0) do |index|
|
|
187
|
+
# reject: skip over responses that are unchanged
|
|
188
|
+
unless values.reject! {|value| value == @answers[index]}
|
|
189
|
+
# remove any answers that don't match the posted values
|
|
190
|
+
@mark_for_destroy << @answers[index] # destroy from database later
|
|
191
|
+
@answers.delete_at(index)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# insert any new answers
|
|
196
|
+
for value in values
|
|
197
|
+
if @mark_for_destroy.empty?
|
|
198
|
+
answer = Fe::Answer.new(:question_id => self.id)
|
|
199
|
+
else
|
|
200
|
+
# re-use marked answers (an update vs. a delete+insert)
|
|
201
|
+
answer = @mark_for_destroy.pop
|
|
202
|
+
end
|
|
203
|
+
answer.set(value)
|
|
204
|
+
@answers << answer
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def save_file(answer_sheet, file)
|
|
210
|
+
@answers.collect(&:destroy) if @answers
|
|
211
|
+
Fe::Answer.create!(:question_id => self.id, :answer_sheet_id => answer_sheet.id, :attachment => file)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# save this question's @answers to database
|
|
215
|
+
def save_response(answer_sheet)
|
|
216
|
+
unless @answers.nil?
|
|
217
|
+
for answer in @answers
|
|
218
|
+
if answer.is_a?(Fe::Answer)
|
|
219
|
+
answer.answer_sheet_id = answer_sheet.id
|
|
220
|
+
answer.save!
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# remove others
|
|
226
|
+
unless @mark_for_destroy.nil?
|
|
227
|
+
for answer in @mark_for_destroy
|
|
228
|
+
answer.destroy
|
|
229
|
+
end
|
|
230
|
+
@mark_for_destroy.clear
|
|
231
|
+
end
|
|
232
|
+
rescue TypeError
|
|
233
|
+
raise answer.inspect
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# has any sort of non-empty response?
|
|
237
|
+
def has_response?(answer_sheet = nil)
|
|
238
|
+
if answer_sheet.present?
|
|
239
|
+
answers = responses(answer_sheet)
|
|
240
|
+
else
|
|
241
|
+
answers = Fe::Answer.where(:question_id => self.id)
|
|
242
|
+
end
|
|
243
|
+
return false if answers.length == 0
|
|
244
|
+
answers.each do |answer| # loop through Answers
|
|
245
|
+
value = answer.is_a?(Fe::Answer) ? answer.value : answer
|
|
246
|
+
return true if (value.is_a?(FalseClass) && value === false) || value.present?
|
|
247
|
+
end
|
|
248
|
+
false
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def required?(answer_sheet = nil)
|
|
252
|
+
super || (answer_sheet && choice_field && choice_field.has_answer?('1', answer_sheet))
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
end
|
|
256
|
+
end
|