surveyor 0.21.0 → 0.22.0

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