surveyor 0.21.0 → 0.22.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.
Files changed (73) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +0 -6
  3. data/README.md +40 -14
  4. data/app/helpers/surveyor_helper.rb +1 -85
  5. data/app/views/partials/_answer.html.haml +5 -4
  6. data/app/views/partials/_question.html.haml +7 -5
  7. data/app/views/partials/_question_group.html.haml +2 -2
  8. data/app/views/surveyor/export.json.rabl +75 -0
  9. data/app/views/surveyor/show.html.haml +75 -13
  10. data/app/views/surveyor/show.json.rabl +14 -0
  11. data/config/routes.rb +2 -3
  12. data/doc/surveyor reject or delete decision matrix.png +0 -0
  13. data/features/export_to_json.feature +96 -0
  14. data/features/show_survey.feature +42 -0
  15. data/features/step_definitions/{common_setps.rb → common_steps.rb} +0 -0
  16. data/features/step_definitions/surveyor_steps.rb +46 -12
  17. data/features/step_definitions/web_steps.rb +15 -5
  18. data/features/support/paths.rb +2 -1
  19. data/features/surveyor.feature +192 -41
  20. data/features/surveyor_parser.feature +10 -10
  21. data/features/{redcap_parser.feature → z_redcap_parser.feature} +9 -6
  22. data/lib/formtastic/surveyor_builder.rb +1 -4
  23. data/lib/generators/surveyor/install_generator.rb +6 -5
  24. data/lib/generators/surveyor/templates/db/migrate/add_api_id_to_question_groups.rb +9 -0
  25. data/lib/generators/surveyor/templates/db/migrate/add_api_ids_to_response_sets_and_responses.rb +11 -0
  26. data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui-timepicker-addon.js +1277 -0
  27. data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery-ui.js +11729 -0
  28. data/lib/generators/surveyor/templates/public/javascripts/surveyor/jquery.surveyor.js +54 -10
  29. data/lib/generators/surveyor/templates/public/stylesheets/sass/surveyor.sass +1 -1
  30. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui-timepicker-addon.css +6 -0
  31. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/jquery-ui.custom.css +572 -0
  32. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  33. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  34. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_glass_65_ffffff_1x400.png +0 -0
  35. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  36. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  37. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ef8c08_256x240.png +0 -0
  38. data/lib/generators/surveyor/templates/public/stylesheets/surveyor/ui-icons_ffffff_256x240.png +0 -0
  39. data/lib/generators/surveyor/templates/surveys/EXTENDING_SURVEYOR.md +14 -0
  40. data/lib/generators/surveyor/templates/surveys/MODIFYING_SURVEYOR.md +91 -0
  41. data/lib/generators/surveyor/templates/surveys/date_survey.rb +15 -0
  42. data/lib/generators/surveyor/templates/surveys/kitchen_sink_survey.rb +2 -2
  43. data/lib/surveyor/common.rb +31 -4
  44. data/lib/surveyor/helpers/surveyor_helper_methods.rb +99 -0
  45. data/lib/surveyor/models/answer_methods.rb +6 -5
  46. data/lib/surveyor/models/dependency_condition_methods.rb +0 -1
  47. data/lib/surveyor/models/dependency_methods.rb +1 -1
  48. data/lib/surveyor/models/question_group_methods.rb +5 -0
  49. data/lib/surveyor/models/question_methods.rb +5 -2
  50. data/lib/surveyor/models/response_methods.rb +44 -3
  51. data/lib/surveyor/models/response_set_methods.rb +14 -4
  52. data/lib/surveyor/models/survey_methods.rb +8 -2
  53. data/lib/surveyor/models/survey_section_methods.rb +13 -1
  54. data/lib/surveyor/parser.rb +18 -11
  55. data/lib/surveyor/render_text.rb +19 -0
  56. data/lib/surveyor/surveyor_controller_methods.rb +19 -1
  57. data/lib/surveyor/unparser.rb +1 -1
  58. data/lib/surveyor/version.rb +1 -1
  59. data/lib/tasks/surveyor_tasks.rake +1 -1
  60. data/spec/controllers/surveyor_controller_spec.rb +7 -3
  61. data/spec/helpers/surveyor_helper_spec.rb +104 -9
  62. data/spec/lib/chinese_survey.rb +14 -0
  63. data/spec/lib/common_spec.rb +52 -1
  64. data/spec/lib/rake_kitchen_sink.rb +40 -0
  65. data/spec/models/answer_spec.rb +11 -0
  66. data/spec/models/question_spec.rb +15 -0
  67. data/spec/models/response_set_spec.rb +45 -1
  68. data/spec/models/response_spec.rb +7 -4
  69. data/surveyor.gemspec +4 -2
  70. metadata +99 -40
  71. data/app/controllers/results_controller.rb +0 -13
  72. data/app/views/results/index.html.erb +0 -17
  73. data/app/views/results/show.html.erb +0 -25
@@ -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
+ });
@@ -0,0 +1,15 @@
1
+ survey "Date Survey" do
2
+
3
+ section "Simple date questions" do
4
+
5
+ q "What is your birth date?"
6
+ a :date
7
+
8
+ q "At what time were you born?"
9
+ a :time
10
+
11
+ q "When would you like to schedule your next appointment?"
12
+ a :datetime
13
+
14
+ end
15
+ end
@@ -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 "Quantity", :float
113
+ a :float
114
114
 
115
115
  q "Unit", :pick => :one, :display_type => :dropdown
116
116
  a "Barrels"
@@ -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/s, ' ') # Remove html tags
19
+ col_text = text.to_s.gsub(/(<[^>]*>)|\n|\t/su, ' ') # Remove html tags
18
20
  col_text.downcase! # Remove capitalization
19
- col_text.gsub!(/\"|\'/, '') # Remove potential problem characters
20
- col_text.gsub!(/\(.*?\)/,'') # Remove text inside parens
21
- col_text.gsub!(/\W/, ' ') # Remove all other non-word characters
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
+ "&nbsp;&nbsp;You answered &quot;#{trigger_responses.join("&quot; and &quot;")}&quot; to the question &quot;#{dependent_questions.map(&:text).join("&quot;,&quot;")}&quot;"
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? ? "&nbsp;" : text.split("|")[0], :postfix => text.split("|")[1] || "&nbsp;"}
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 'uuid'
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 ||= UUID.generate
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
@@ -61,7 +61,6 @@ module Surveyor
61
61
  false
62
62
  end
63
63
  end
64
-
65
64
  protected
66
65
 
67
66
  def validates_operator
@@ -51,7 +51,7 @@ module Surveyor
51
51
  hash = {}
52
52
  self.dependency_conditions.each{|dc| hash.merge!(dc.to_hash(response_set))}
53
53
  return hash
54
- end
54
+ end
55
55
  end
56
56
  end
57
57
  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 'uuid'
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 ||= UUID.generate
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, :response_set_id, :question_id, :answer_id
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