surveyor 0.21.0 → 0.22.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Gemfile +0 -6
- data/README.md +40 -14
- data/app/helpers/surveyor_helper.rb +1 -85
- data/app/views/partials/_answer.html.haml +5 -4
- data/app/views/partials/_question.html.haml +7 -5
- data/app/views/partials/_question_group.html.haml +2 -2
- data/app/views/surveyor/export.json.rabl +75 -0
- data/app/views/surveyor/show.html.haml +75 -13
- data/app/views/surveyor/show.json.rabl +14 -0
- data/config/routes.rb +2 -3
- data/doc/surveyor reject or delete decision matrix.png +0 -0
- data/features/export_to_json.feature +96 -0
- data/features/show_survey.feature +42 -0
- data/features/step_definitions/{common_setps.rb → common_steps.rb} +0 -0
- data/features/step_definitions/surveyor_steps.rb +46 -12
- data/features/step_definitions/web_steps.rb +15 -5
- data/features/support/paths.rb +2 -1
- data/features/surveyor.feature +192 -41
- data/features/surveyor_parser.feature +10 -10
- data/features/{redcap_parser.feature → z_redcap_parser.feature} +9 -6
- data/lib/formtastic/surveyor_builder.rb +1 -4
- data/lib/generators/surveyor/install_generator.rb +6 -5
- data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +9 -0
- data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +11 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui-timepicker-addon.js +1277 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui.js +11729 -0
- data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery.surveyor.js +54 -10
- data/lib/generators/surveyor/templates/public/stylesheets/sass/surveyor.sass +1 -1
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui-timepicker-addon.css +6 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui.custom.css +572 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ef8c08_256x240.png +0 -0
- data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ffffff_256x240.png +0 -0
- data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +14 -0
- data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
- data/lib/generators/surveyor/templates/surveys/date_survey.rb +15 -0
- data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +2 -2
- data/lib/surveyor/common.rb +31 -4
- data/lib/surveyor/helpers/surveyor_helper_methods.rb +99 -0
- data/lib/surveyor/models/answer_methods.rb +6 -5
- data/lib/surveyor/models/dependency_condition_methods.rb +0 -1
- data/lib/surveyor/models/dependency_methods.rb +1 -1
- data/lib/surveyor/models/question_group_methods.rb +5 -0
- data/lib/surveyor/models/question_methods.rb +5 -2
- data/lib/surveyor/models/response_methods.rb +44 -3
- data/lib/surveyor/models/response_set_methods.rb +14 -4
- data/lib/surveyor/models/survey_methods.rb +8 -2
- data/lib/surveyor/models/survey_section_methods.rb +13 -1
- data/lib/surveyor/parser.rb +18 -11
- data/lib/surveyor/render_text.rb +19 -0
- data/lib/surveyor/surveyor_controller_methods.rb +19 -1
- data/lib/surveyor/unparser.rb +1 -1
- data/lib/surveyor/version.rb +1 -1
- data/lib/tasks/surveyor_tasks.rake +1 -1
- data/spec/controllers/surveyor_controller_spec.rb +7 -3
- data/spec/helpers/surveyor_helper_spec.rb +104 -9
- data/spec/lib/chinese_survey.rb +14 -0
- data/spec/lib/common_spec.rb +52 -1
- data/spec/lib/rake_kitchen_sink.rb +40 -0
- data/spec/models/answer_spec.rb +11 -0
- data/spec/models/question_spec.rb +15 -0
- data/spec/models/response_set_spec.rb +45 -1
- data/spec/models/response_spec.rb +7 -4
- data/surveyor.gemspec +4 -2
- metadata +99 -40
- data/app/controllers/results_controller.rb +0 -13
- data/app/views/results/index.html.erb +0 -17
- data/app/views/results/show.html.erb +0 -25
data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_f6f6f6_1x400.png
ADDED
Binary file
|
data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_fdf5ce_1x400.png
ADDED
Binary file
|
data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_65_ffffff_1x400.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ef8c08_256x240.png
ADDED
Binary file
|
data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ffffff_256x240.png
ADDED
Binary file
|
@@ -29,6 +29,20 @@ For example, create app/models/survey.rb with the following contents:
|
|
29
29
|
|
30
30
|
== SurveyorHelper
|
31
31
|
|
32
|
+
The SurveyorHelper module can be customized just like the models:
|
33
|
+
|
34
|
+
module SurveyorHelper
|
35
|
+
include Surveyor::Helpers::SurveyorHelperMethods
|
36
|
+
def rc_to_as(type_sym)
|
37
|
+
case type_sym.to_s
|
38
|
+
when /(integer|float)/ then :string
|
39
|
+
when /(datetime)/ then :string
|
40
|
+
when /^date$/ then :string
|
41
|
+
else type_sym
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
32
46
|
== Views
|
33
47
|
|
34
48
|
Surveyor's views can be overwritten by simply creating views in app/views/surveyor
|
@@ -0,0 +1,91 @@
|
|
1
|
+
== Dates, Times, and Javascript Date Picker
|
2
|
+
|
3
|
+
== Default JQuery Date Picker
|
4
|
+
|
5
|
+
By default Surveyor uses the JQuery-UI date picker (http://jqueryui.com/demos/datepicker/)
|
6
|
+
for all date and time fields (denoted by :date, :time, or :datetime for the answer in the survey).
|
7
|
+
|
8
|
+
== Using Rails Date Helpers
|
9
|
+
|
10
|
+
It is possible (and relatively easy) to use the default Rails
|
11
|
+
date helpers (http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html)
|
12
|
+
instead of the javascript date picker.
|
13
|
+
|
14
|
+
To do so you would need to override two methods in the SurveyorHelperMethods. Currently the
|
15
|
+
rc_to_attr and rc_to_as handle how the form fields are displayed. The formtastic input method
|
16
|
+
(https://github.com/justinfrench/formtastic) used in the _answer.html.haml partial
|
17
|
+
calls the rc_to_attr method to get the attribute for the answer object
|
18
|
+
and then calls the rc_to_as method to get the value to set the :as parameter.
|
19
|
+
|
20
|
+
ff.input rc_to_attr(a.response_class), :as => rc_to_as(a.response_class)
|
21
|
+
|
22
|
+
def rc_to_attr(type_sym)
|
23
|
+
case type_sym.to_s
|
24
|
+
when /^answer$/ then :answer_id
|
25
|
+
else "#{type_sym.to_s}_value".to_sym
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def rc_to_as(type_sym)
|
30
|
+
case type_sym.to_s
|
31
|
+
when /(integer|float|date|time|datetime)/ then :string
|
32
|
+
else type_sym
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
First, we would need to set that the attribute to be used is the :datetime_value attribute on the
|
37
|
+
answer. (By default we use the custom date_value and time_value methods which wrap the :datetime_value
|
38
|
+
on the answer to work with the string representation of those values). To do this we would need to
|
39
|
+
change the rc_to_attr method so that either the date or time types return the :datetime_value attribute
|
40
|
+
|
41
|
+
def rc_to_attr(type_sym)
|
42
|
+
case type_sym.to_s
|
43
|
+
when /^date|time$/ then :datetime_value
|
44
|
+
when /^(string|text|integer|float|datetime)$/ then "#{type_sym.to_s}_value".to_sym
|
45
|
+
else :answer_id
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
Second, we would need to update the rc_to_as method so that the date, time, and/or datetime
|
51
|
+
answer types would return those values rather than string as they do by default
|
52
|
+
|
53
|
+
def rc_to_as(type_sym)
|
54
|
+
case type_sym.to_s
|
55
|
+
when /(integer|float)/ then :string
|
56
|
+
else type_sym
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
Of course, you could mix and match which attribute types could be show with the Rails Date Helper
|
61
|
+
methods and which ones could use the javascript date picker.
|
62
|
+
|
63
|
+
== JQuery Tools Date Input
|
64
|
+
|
65
|
+
If you would like to use JQuery Tools dateinput instead (http://jquerytools.org/demos/dateinput/index.html)
|
66
|
+
you would need to edit the
|
67
|
+
vendor/assets/javascripts/surveyor/jquery.surveyor.js file.
|
68
|
+
|
69
|
+
Replace the jquery-ui datepicker lines:
|
70
|
+
|
71
|
+
jQuery("input[type='text'].date").datepicker({
|
72
|
+
dateFormat: 'yy-mm-dd',
|
73
|
+
changeMonth: true,
|
74
|
+
changeYear: true
|
75
|
+
});
|
76
|
+
|
77
|
+
with those for the jquery tools dateinput
|
78
|
+
|
79
|
+
jQuery('li input.date').dateinput({
|
80
|
+
format: 'dd mmm yyyy'
|
81
|
+
});
|
82
|
+
|
83
|
+
(note that you may need to add the following to make the jquery tools dateinput widget to work properly)
|
84
|
+
|
85
|
+
jQuery('li.date input').change(function(){
|
86
|
+
if ( $(this).data('dateinput') ) {
|
87
|
+
var date_obj = $(this).data('dateinput').getValue();
|
88
|
+
this.value = date_obj.getFullYear() + "-" + (date_obj.getMonth()+1) + "-" +
|
89
|
+
date_obj.getDate() + " 00:00:00 UTC";
|
90
|
+
}
|
91
|
+
});
|
@@ -25,7 +25,7 @@ survey "Kitchen Sink survey" do
|
|
25
25
|
# the question's reference identifier is "2a", and the answer's reference_identifier is "1"
|
26
26
|
# question reference identifiers used in conditions need to be unique on a survey for the lookups to work
|
27
27
|
q_2a "Please explain why you don't like this color?"
|
28
|
-
a_1 "explanation", :text
|
28
|
+
a_1 "explanation", :text, :help_text => "Please give an explanation for each color you don't like"
|
29
29
|
dependency :rule => "A or B or C or D"
|
30
30
|
condition_A :q_2, "==", :a_1
|
31
31
|
condition_B :q_2, "==", :a_2
|
@@ -110,7 +110,7 @@ survey "Kitchen Sink survey" do
|
|
110
110
|
# Questions may be grouped
|
111
111
|
group "How much oil do you use per day?", :display_type => :inline do
|
112
112
|
q "Quantity"
|
113
|
-
a
|
113
|
+
a :float
|
114
114
|
|
115
115
|
q "Unit", :pick => :one, :display_type => :dropdown
|
116
116
|
a "Barrels"
|
data/lib/surveyor/common.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'uuidtools'
|
2
|
+
|
1
3
|
module Surveyor
|
2
4
|
class Common
|
3
5
|
RAND_CHARS = [('a'..'z'), ('A'..'Z'), (0..9)].map{|r| r.to_a}.flatten.join
|
@@ -14,17 +16,42 @@ module Surveyor
|
|
14
16
|
|
15
17
|
def to_normalized_string(text)
|
16
18
|
words_to_omit = %w(a be but has have in is it of on or the to when)
|
17
|
-
col_text = text.to_s.gsub(/(<[^>]*>)|\n|\t/
|
19
|
+
col_text = text.to_s.gsub(/(<[^>]*>)|\n|\t/su, ' ') # Remove html tags
|
18
20
|
col_text.downcase! # Remove capitalization
|
19
|
-
col_text.gsub!(/\"|\'
|
20
|
-
col_text.gsub!(/\(.*?\)
|
21
|
-
col_text.gsub!(/\W
|
21
|
+
col_text.gsub!(/\"|\'/u, '') # Remove potential problem characters
|
22
|
+
col_text.gsub!(/\(.*?\)/u,'') # Remove text inside parens
|
23
|
+
col_text.gsub!(/\W/u, ' ') # Remove all other non-word characters
|
22
24
|
cols = (col_text.split(' ') - words_to_omit)
|
23
25
|
(cols.size > 5 ? cols[-5..-1] : cols).join("_")
|
24
26
|
end
|
25
27
|
|
28
|
+
def equal_json_excluding_wildcards(a,b)
|
29
|
+
return false if a.nil? or b.nil?
|
30
|
+
a = a.is_a?(String) ? JSON.load(a) : JSON.load(a.to_json)
|
31
|
+
b = b.is_a?(String) ? JSON.load(b) : JSON.load(b.to_json)
|
32
|
+
deep_compare_excluding_wildcards(a,b)
|
33
|
+
end
|
34
|
+
def deep_compare_excluding_wildcards(a,b)
|
35
|
+
return false if a.class != b.class
|
36
|
+
if a.is_a?(Hash)
|
37
|
+
return false if a.size != b.size
|
38
|
+
a.each do |k,v|
|
39
|
+
return false if deep_compare_excluding_wildcards(v,b[k]) == false
|
40
|
+
end
|
41
|
+
elsif a.is_a?(Array)
|
42
|
+
return false if a.size != b.size
|
43
|
+
a.each_with_index{|e,i| return false if deep_compare_excluding_wildcards(e,b[i]) == false }
|
44
|
+
else
|
45
|
+
return (a == "*") || (b == "*") || (a == b)
|
46
|
+
end
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
26
50
|
alias :normalize :to_normalized_string
|
27
51
|
|
52
|
+
def generate_api_id
|
53
|
+
UUIDTools::UUID.random_create.to_s
|
54
|
+
end
|
28
55
|
end
|
29
56
|
end
|
30
57
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Surveyor
|
2
|
+
module Helpers
|
3
|
+
module SurveyorHelperMethods
|
4
|
+
# Layout: stylsheets and javascripts
|
5
|
+
def surveyor_includes
|
6
|
+
surveyor_stylsheets + surveyor_javascripts
|
7
|
+
end
|
8
|
+
def surveyor_stylsheets
|
9
|
+
stylesheet_link_tag 'surveyor/reset', 'surveyor/dateinput', 'surveyor/jquery-ui.custom', 'surveyor/jquery-ui-timepicker-addon', 'surveyor', 'custom'
|
10
|
+
end
|
11
|
+
def surveyor_javascripts
|
12
|
+
javascript_include_tag 'surveyor/jquery.tools.min', 'surveyor/jquery-ui', 'surveyor/jquery-ui-timepicker-addon', 'surveyor/jquery.surveyor', 'surveyor/jquery.blockUI'
|
13
|
+
end
|
14
|
+
# Helper for displaying warning/notice/error flash messages
|
15
|
+
def flash_messages(types)
|
16
|
+
types.map{|type| content_tag(:div, "#{flash[type]}".html_safe, :class => type.to_s)}.join.html_safe
|
17
|
+
end
|
18
|
+
# Section: dependencies, menu, previous and next
|
19
|
+
def dependency_explanation_helper(question,response_set)
|
20
|
+
# Attempts to explain why this dependent question needs to be answered by referenced the dependent question and users response
|
21
|
+
trigger_responses = []
|
22
|
+
dependent_questions = Question.find_all_by_id(question.dependency.dependency_conditions.map(&:question_id)).uniq
|
23
|
+
response_set.responses.find_all_by_question_id(dependent_questions.map(&:id)).uniq.each do |resp|
|
24
|
+
trigger_responses << resp.to_s
|
25
|
+
end
|
26
|
+
" You answered "#{trigger_responses.join("" and "")}" to the question "#{dependent_questions.map(&:text).join("","")}""
|
27
|
+
end
|
28
|
+
def menu_button_for(section)
|
29
|
+
submit_tag(section.title, :name => "section[#{section.id}]")
|
30
|
+
end
|
31
|
+
def previous_section
|
32
|
+
# use copy in memory instead of making extra db calls
|
33
|
+
submit_tag(t('surveyor.previous_section').html_safe, :name => "section[#{@sections[@sections.index(@section)-1].id}]") unless @sections.first == @section
|
34
|
+
end
|
35
|
+
def next_section
|
36
|
+
# use copy in memory instead of making extra db calls
|
37
|
+
@sections.last == @section ? submit_tag(t('surveyor.click_here_to_finish').html_safe, :name => "finish") : submit_tag(t('surveyor.next_section').html_safe, :name => "section[#{@sections[@sections.index(@section)+1].id}]")
|
38
|
+
end
|
39
|
+
|
40
|
+
# Questions
|
41
|
+
def q_text(obj, context=nil)
|
42
|
+
@n ||= 0
|
43
|
+
return image_tag(obj.text) if obj.is_a?(Question) and obj.display_type == "image"
|
44
|
+
return obj.render_question_text(context) if obj.is_a?(Question) and (obj.dependent? or obj.display_type == "label" or obj.part_of_group?)
|
45
|
+
"#{@n += 1}) #{obj.render_question_text(context)}"
|
46
|
+
end
|
47
|
+
# def split_text(text = "") # Split text into with "|" delimiter - parts to go before/after input element
|
48
|
+
# {:prefix => text.split("|")[0].blank? ? " " : text.split("|")[0], :postfix => text.split("|")[1] || " "}
|
49
|
+
# end
|
50
|
+
# def question_help_helper(question)
|
51
|
+
# question.help_text.blank? ? "" : %Q(<span class="question-help">#{question.help_text}</span>)
|
52
|
+
# end
|
53
|
+
|
54
|
+
# Help_text
|
55
|
+
def render_help_text(obj, context=nil)
|
56
|
+
obj.render_help_text(context)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Answers
|
60
|
+
def a_text(obj, pos=nil, context = nil)
|
61
|
+
return image_tag(obj.text) if obj.is_a?(Answer) and obj.display_type == "image"
|
62
|
+
obj.split_or_hidden_text(pos, context)
|
63
|
+
end
|
64
|
+
|
65
|
+
def rc_to_attr(type_sym)
|
66
|
+
case type_sym.to_s
|
67
|
+
when /^answer$/ then :answer_id
|
68
|
+
else "#{type_sym.to_s}_value".to_sym
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def rc_to_as(type_sym)
|
73
|
+
case type_sym.to_s
|
74
|
+
when /(integer|float|date|time|datetime)/ then :string
|
75
|
+
else type_sym
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_pick_none_input_html(value, default_value, css_class, response_class, disabled)
|
80
|
+
html = {}
|
81
|
+
html[:class] = [response_class,css_class].reject{ |c| c.blank? }
|
82
|
+
html[:value] = default_value if value.blank?
|
83
|
+
html[:disabled] = disabled unless disabled.blank?
|
84
|
+
html
|
85
|
+
end
|
86
|
+
|
87
|
+
# Responses
|
88
|
+
def response_for(response_set, question, answer = nil, response_group = nil)
|
89
|
+
return nil unless response_set && question && question.id
|
90
|
+
result = response_set.responses.detect{|r| (r.question_id == question.id) && (answer.blank? ? true : r.answer_id == answer.id) && (r.response_group.blank? ? true : r.response_group.to_i == response_group.to_i)}
|
91
|
+
result.blank? ? response_set.responses.build(:question_id => question.id, :response_group => response_group) : result
|
92
|
+
end
|
93
|
+
def response_idx(increment = true)
|
94
|
+
@rc ||= 0
|
95
|
+
(increment ? @rc += 1 : @rc).to_s
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'surveyor/common'
|
2
2
|
|
3
3
|
module Surveyor
|
4
4
|
module Models
|
@@ -21,6 +21,8 @@ module Surveyor
|
|
21
21
|
@@validations_already_included = true
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
include RenderText
|
24
26
|
|
25
27
|
# Instance Methods
|
26
28
|
def initialize(*args)
|
@@ -34,18 +36,17 @@ module Surveyor
|
|
34
36
|
self.response_class ||= "answer"
|
35
37
|
self.short_text ||= text
|
36
38
|
self.data_export_identifier ||= Surveyor::Common.normalize(text)
|
37
|
-
self.api_id ||=
|
39
|
+
self.api_id ||= Surveyor::Common.generate_api_id
|
38
40
|
end
|
39
41
|
|
40
42
|
def css_class
|
41
43
|
[(is_exclusive ? "exclusive" : nil), custom_class].compact.join(" ")
|
42
44
|
end
|
43
45
|
|
44
|
-
def split_or_hidden_text(part = nil)
|
46
|
+
def split_or_hidden_text(part = nil, context = nil)
|
45
47
|
return "" if display_type == "hidden_label"
|
46
|
-
part == :pre ? text.split("|",2)[0] : (part == :post ? text.split("|",2)[1] : text)
|
48
|
+
part == :pre ? self.render_answer_text(text.split("|",2)[0], context) : (part == :post ? self.render_answer_text(text.split("|",2)[1], context) : self.render_answer_text(text, context))
|
47
49
|
end
|
48
|
-
|
49
50
|
end
|
50
51
|
end
|
51
52
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'surveyor/common'
|
2
|
+
|
1
3
|
module Surveyor
|
2
4
|
module Models
|
3
5
|
module QuestionGroupMethods
|
@@ -6,6 +8,8 @@ module Surveyor
|
|
6
8
|
base.send :has_many, :questions
|
7
9
|
base.send :has_one, :dependency
|
8
10
|
end
|
11
|
+
|
12
|
+
include RenderText
|
9
13
|
|
10
14
|
# Instance Methods
|
11
15
|
def initialize(*args)
|
@@ -15,6 +19,7 @@ module Surveyor
|
|
15
19
|
|
16
20
|
def default_args
|
17
21
|
self.display_type ||= "inline"
|
22
|
+
self.api_id ||= Surveyor::Common.generate_api_id
|
18
23
|
end
|
19
24
|
|
20
25
|
def renderer
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require '
|
1
|
+
require 'surveyor/common'
|
2
2
|
|
3
3
|
module Surveyor
|
4
4
|
module Models
|
@@ -23,9 +23,12 @@ module Surveyor
|
|
23
23
|
base.send :validates_inclusion_of, :is_mandatory, :in => [true, false]
|
24
24
|
|
25
25
|
@@validations_already_included = true
|
26
|
+
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
30
|
+
include RenderText
|
31
|
+
|
29
32
|
# Instance Methods
|
30
33
|
def initialize(*args)
|
31
34
|
super(*args)
|
@@ -38,7 +41,7 @@ module Surveyor
|
|
38
41
|
self.pick ||= "none"
|
39
42
|
self.data_export_identifier ||= Surveyor::Common.normalize(text)
|
40
43
|
self.short_text ||= text
|
41
|
-
self.api_id ||=
|
44
|
+
self.api_id ||= Surveyor::Common.generate_api_id
|
42
45
|
end
|
43
46
|
|
44
47
|
def pick=(val)
|
@@ -6,15 +6,19 @@ module Surveyor
|
|
6
6
|
base.send :belongs_to, :response_set
|
7
7
|
base.send :belongs_to, :question
|
8
8
|
base.send :belongs_to, :answer
|
9
|
+
|
10
|
+
# Scopes
|
11
|
+
base.send :default_scope, :order => "created_at ASC"
|
12
|
+
|
9
13
|
@@validations_already_included ||= nil
|
10
14
|
unless @@validations_already_included
|
11
15
|
# Validations
|
12
|
-
base.send :validates_presence_of, :
|
13
|
-
|
16
|
+
base.send :validates_presence_of, :question_id, :answer_id
|
17
|
+
|
14
18
|
@@validations_already_included = true
|
15
19
|
end
|
16
20
|
base.send :include, Surveyor::ActsAsResponse # includes "as" instance method
|
17
|
-
|
21
|
+
|
18
22
|
# Class methods
|
19
23
|
base.instance_eval do
|
20
24
|
def applicable_attributes(attrs)
|
@@ -30,6 +34,15 @@ module Surveyor
|
|
30
34
|
end
|
31
35
|
|
32
36
|
# Instance Methods
|
37
|
+
def initialize(*args)
|
38
|
+
super(*args)
|
39
|
+
default_args
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_args
|
43
|
+
self.api_id ||= Surveyor::Common.generate_api_id
|
44
|
+
end
|
45
|
+
|
33
46
|
def answer_id=(val)
|
34
47
|
write_attribute :answer_id, (val.is_a?(Array) ? val.detect{|x| !x.to_s.blank?} : val)
|
35
48
|
end
|
@@ -37,6 +50,34 @@ module Surveyor
|
|
37
50
|
question.correct_answer.nil? or self.answer.response_class != "answer" or (question.correct_answer.id.to_i == answer.id.to_i)
|
38
51
|
end
|
39
52
|
|
53
|
+
def time_value
|
54
|
+
read_attribute(:datetime_value).strftime( time_format ) unless read_attribute(:datetime_value).blank?
|
55
|
+
end
|
56
|
+
|
57
|
+
def time_value=(val)
|
58
|
+
self.datetime_value = Time.zone.parse("#{Date.today.to_s} #{val}").to_datetime
|
59
|
+
end
|
60
|
+
|
61
|
+
def date_value
|
62
|
+
read_attribute(:datetime_value).strftime( date_format ) unless read_attribute(:datetime_value).blank?
|
63
|
+
end
|
64
|
+
|
65
|
+
def date_value=(val)
|
66
|
+
self.datetime_value = Time.zone.parse(val).to_datetime
|
67
|
+
end
|
68
|
+
|
69
|
+
def time_format
|
70
|
+
'%H:%M'
|
71
|
+
end
|
72
|
+
|
73
|
+
def date_format
|
74
|
+
'%Y-%m-%d'
|
75
|
+
end
|
76
|
+
|
77
|
+
def datetime_format
|
78
|
+
'%Y-%m-%d %H:%M'
|
79
|
+
end
|
80
|
+
|
40
81
|
def to_s # used in dependency_explanation_helper
|
41
82
|
if self.answer.response_class == "answer" and self.answer_id
|
42
83
|
return self.answer.text
|