formbuilder-rb 0.0.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/Gemfile +14 -0
  7. data/Gemfile.lock +219 -0
  8. data/Guardfile +17 -0
  9. data/{MIT-LICENSE → LICENSE.md} +1 -1
  10. data/README.md +86 -0
  11. data/app/controllers/formbuilder/concerns/forms_controller.rb +59 -0
  12. data/app/models/formbuilder/entry_attachment.rb +2 -8
  13. data/app/models/formbuilder/form.rb +53 -0
  14. data/app/models/formbuilder/response_field.rb +23 -10
  15. data/app/models/formbuilder/response_field_address.rb +12 -1
  16. data/app/models/formbuilder/response_field_checkboxes.rb +38 -0
  17. data/app/models/formbuilder/response_field_date.rb +7 -1
  18. data/app/models/formbuilder/response_field_dropdown.rb +2 -1
  19. data/app/models/formbuilder/response_field_email.rb +14 -2
  20. data/app/models/formbuilder/response_field_file.rb +75 -20
  21. data/app/models/formbuilder/response_field_number.rb +9 -2
  22. data/app/models/formbuilder/response_field_page_break.rb +13 -0
  23. data/app/models/formbuilder/response_field_paragraph.rb +19 -3
  24. data/app/models/formbuilder/response_field_price.rb +10 -6
  25. data/app/models/formbuilder/response_field_radio.rb +11 -2
  26. data/app/models/formbuilder/response_field_section_break.rb +12 -2
  27. data/app/models/formbuilder/response_field_table.rb +222 -0
  28. data/app/models/formbuilder/response_field_text.rb +9 -2
  29. data/app/models/formbuilder/response_field_time.rb +8 -1
  30. data/app/models/formbuilder/response_field_website.rb +26 -2
  31. data/app/uploaders/formbuilder/entry_attachment_uploader.rb +11 -1
  32. data/bin/rails +8 -0
  33. data/circle.yml +9 -0
  34. data/config/spring.rb +1 -0
  35. data/db/migrate/20130924185815_create_formbuilder_entry_attachments.rb +1 -0
  36. data/formbuilder-rb.gemspec +41 -0
  37. data/formbuilder-rb.sublime-project +20 -0
  38. data/lib/formbuilder.rb +8 -3
  39. data/lib/formbuilder/entry.rb +102 -159
  40. data/lib/formbuilder/entry_validator.rb +13 -6
  41. data/lib/formbuilder/version.rb +1 -1
  42. data/lib/formbuilder/views/entry_dl.rb +56 -0
  43. data/lib/formbuilder/views/form.rb +81 -0
  44. data/lib/formbuilder/views/form_field.rb +45 -0
  45. data/spec/controllers/formbuilder/forms_controller_spec.rb +40 -0
  46. data/spec/dummy/.ruby-gemset +1 -0
  47. data/spec/dummy/.ruby-version +1 -0
  48. data/spec/dummy/README.rdoc +28 -0
  49. data/spec/dummy/Rakefile +6 -0
  50. data/spec/dummy/app/assets/images/.keep +0 -0
  51. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  52. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  53. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  54. data/spec/dummy/app/controllers/forms_controller.rb +3 -0
  55. data/spec/dummy/app/controllers/test_controller.rb +57 -0
  56. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  57. data/spec/dummy/app/mailers/.keep +0 -0
  58. data/spec/dummy/app/models/concerns/.keep +0 -0
  59. data/spec/dummy/app/models/entry.rb +7 -0
  60. data/spec/dummy/app/models/entry_with_alternate_column_name.rb +11 -0
  61. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  62. data/spec/dummy/app/views/test/_form.rb +2 -0
  63. data/spec/dummy/app/views/test/render_entry.html.erb +1 -0
  64. data/spec/dummy/app/views/test/show_form.html.erb +1 -0
  65. data/spec/dummy/bin/bundle +3 -0
  66. data/spec/dummy/bin/rails +4 -0
  67. data/spec/dummy/bin/rake +4 -0
  68. data/spec/dummy/config.ru +4 -0
  69. data/spec/dummy/config/application.rb +25 -0
  70. data/spec/dummy/config/boot.rb +5 -0
  71. data/spec/dummy/config/database.yml.ci +15 -0
  72. data/spec/dummy/config/database.yml.example +15 -0
  73. data/spec/dummy/config/environment.rb +5 -0
  74. data/spec/dummy/config/environments/development.rb +29 -0
  75. data/spec/dummy/config/environments/production.rb +80 -0
  76. data/spec/dummy/config/environments/test.rb +52 -0
  77. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  78. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  79. data/spec/dummy/config/initializers/inflections.rb +16 -0
  80. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  81. data/spec/dummy/config/initializers/secret_token.rb +12 -0
  82. data/spec/dummy/config/initializers/session_store.rb +3 -0
  83. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  84. data/spec/dummy/config/locales/en.yml +23 -0
  85. data/spec/dummy/config/routes.rb +12 -0
  86. data/spec/dummy/db/migrate/20130924182939_create_entries.rb +13 -0
  87. data/spec/dummy/db/migrate/20130924192151_create_formbuilder_forms.formbuilder.rb +11 -0
  88. data/spec/dummy/db/migrate/20130924192152_create_formbuilder_response_fields.formbuilder.rb +17 -0
  89. data/spec/dummy/db/migrate/20130926205845_create_formbuilder_entry_attachments.formbuilder.rb +12 -0
  90. data/spec/dummy/db/migrate/20140128000000_create_entry_with_alternate_column_names.rb +13 -0
  91. data/spec/dummy/db/schema.rb +64 -0
  92. data/spec/dummy/lib/assets/.keep +0 -0
  93. data/spec/dummy/log/.keep +0 -0
  94. data/spec/dummy/public/404.html +58 -0
  95. data/spec/dummy/public/422.html +58 -0
  96. data/spec/dummy/public/500.html +57 -0
  97. data/spec/dummy/public/favicon.ico +0 -0
  98. data/spec/dummy/test/fixtures/entries.yml +9 -0
  99. data/spec/dummy/test/fixtures/response_fields.yml +19 -0
  100. data/spec/dummy/test/models/entry_test.rb +7 -0
  101. data/spec/dummy/test/models/response_field_test.rb +7 -0
  102. data/spec/factories/formbuilder_forms.rb +45 -0
  103. data/spec/features/form_renderer_spec.rb +30 -0
  104. data/spec/features/submitting_an_entry_spec.rb +79 -0
  105. data/spec/fixtures/test_files/text.txt +1 -0
  106. data/spec/fixtures/test_files/text2.txt +1 -0
  107. data/spec/lib/formbuilder/entry_spec.rb +199 -0
  108. data/spec/lib/formbuilder/entry_validator_spec.rb +215 -0
  109. data/spec/lib/formbuilder/entry_with_alternate_column_name_spec.rb +37 -0
  110. data/spec/lib/formbuilder/views/entry_dl_spec.rb +38 -0
  111. data/spec/models/formbuilder/entry_attachment_spec.rb +17 -0
  112. data/spec/models/formbuilder/form_spec.rb +100 -0
  113. data/spec/models/formbuilder/response_field_address_spec.rb +25 -0
  114. data/spec/models/formbuilder/response_field_checkboxes_spec.rb +57 -0
  115. data/spec/models/formbuilder/response_field_file_spec.rb +80 -0
  116. data/spec/models/formbuilder/response_field_paragraph_spec.rb +22 -0
  117. data/spec/models/formbuilder/response_field_radio_spec.rb +30 -0
  118. data/spec/models/formbuilder/response_field_spec.rb +21 -0
  119. data/spec/models/formbuilder/response_field_table_spec.rb +124 -0
  120. data/spec/spec_helper.rb +25 -0
  121. data/spec/support/database_cleaner.rb +21 -0
  122. data/spec/support/submitting_an_entry_spec_helper.rb +151 -0
  123. metadata +286 -44
  124. data/app/controllers/formbuilder/forms_controller.rb +0 -53
  125. data/lib/formbuilder/entry_renderer.rb +0 -47
  126. data/lib/formbuilder/entry_table_renderer.rb +0 -58
  127. data/lib/formbuilder/form_renderer.rb +0 -102
data/bin/rails ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application.
3
+
4
+ ENGINE_ROOT = File.expand_path('../..', __FILE__)
5
+ ENGINE_PATH = File.expand_path('../../lib/formbuilder/engine', __FILE__)
6
+
7
+ require 'rails/all'
8
+ require 'rails/engine/commands'
data/circle.yml ADDED
@@ -0,0 +1,9 @@
1
+ machine:
2
+ environment:
3
+ COVERALLS_REPO_TOKEN: ppRfiNa1YEa2M9VtGpXw0AOzVqYEUEkFR
4
+
5
+ database:
6
+ override:
7
+ - cp spec/dummy/config/database.yml.ci spec/dummy/config/database.yml
8
+ - bundle exec rake db:create db:schema:load
9
+
data/config/spring.rb ADDED
@@ -0,0 +1 @@
1
+ Spring.application_root = './spec/dummy'
@@ -3,6 +3,7 @@ class CreateFormbuilderEntryAttachments < ActiveRecord::Migration
3
3
  create_table :formbuilder_entry_attachments do |t|
4
4
  t.string :upload
5
5
  t.string :content_type
6
+ t.integer :file_size
6
7
 
7
8
  t.timestamps
8
9
  end
@@ -0,0 +1,41 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "formbuilder/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.name = "formbuilder-rb"
9
+ s.version = Formbuilder::VERSION
10
+ s.authors = ["Adam Becker"]
11
+ s.email = ["adam@dobt.co"]
12
+ s.homepage = "https://github.com/dobtco/formbuilder-rb"
13
+ s.summary = "Build and save custom forms."
14
+ s.description = "This is a Rails Engine for https://github.com/dobtco/formbuilder."
15
+ s.license = "MIT"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {features,spec}/*`.split("\n")
19
+
20
+ s.add_dependency "rails", "4.1.0.rc1"
21
+
22
+ s.add_dependency 'carrierwave'
23
+ s.add_dependency 'erector-rails4'
24
+ s.add_dependency 'geocoder'
25
+ s.add_dependency 'pg'
26
+ s.add_dependency 'rinku'
27
+ s.add_dependency 'rmagick'
28
+
29
+ s.add_development_dependency 'capybara'
30
+ s.add_development_dependency 'database_cleaner'
31
+ s.add_development_dependency 'factory_girl_rails'
32
+ s.add_development_dependency 'guard-rspec'
33
+ s.add_development_dependency 'launchy'
34
+ s.add_development_dependency 'rspec-rails'
35
+ s.add_development_dependency 'spring'
36
+ s.add_development_dependency 'spring-commands-rspec'
37
+ s.add_development_dependency 'terminal-notifier-guard'
38
+ s.add_development_dependency 'thin'
39
+ s.add_development_dependency 'coveralls'
40
+
41
+ end
@@ -0,0 +1,20 @@
1
+ {
2
+ "folders":
3
+ [
4
+ {
5
+ "path": ".",
6
+ "folder_exclude_patterns": ["coverage", "log", "tmp"],
7
+ "file_exclude_patterns": ["*.sublime-workspace", "*.sql"]
8
+ }
9
+ ],
10
+
11
+ "settings":
12
+ {
13
+ // indentation
14
+ "tab_size": 2,
15
+ "translate_tabs_to_spaces": true,
16
+ "trim_trailing_white_space_on_save": true,
17
+ // ensure line endings is linux style (even when on Windows)
18
+ "default_line_ending": "LF"
19
+ }
20
+ }
data/lib/formbuilder.rb CHANGED
@@ -1,9 +1,14 @@
1
+ # Require dependencies explicitly
2
+ require 'carrierwave'
3
+ require 'erector'
4
+ require 'geocoder'
5
+
1
6
  require "formbuilder/engine"
2
7
  require "formbuilder/entry"
3
- require "formbuilder/entry_renderer"
4
- require "formbuilder/entry_table_renderer"
5
8
  require "formbuilder/entry_validator"
6
- require "formbuilder/form_renderer"
9
+ require "formbuilder/views/form"
10
+ require "formbuilder/views/form_field"
11
+ require "formbuilder/views/entry_dl"
7
12
 
8
13
  module Formbuilder
9
14
  def self.root
@@ -3,33 +3,82 @@ module Formbuilder
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- attr_accessor :old_responses
7
- attr_accessor :skip_validation
6
+ attr_accessor :skip_validation, :only_validate_page
7
+
8
+ before_validation :normalize_responses
8
9
  validates_with Formbuilder::EntryValidator
9
- before_save :calculate_responses_text, if: :responses_changed?
10
- include ActionView::Helpers::TextHelper
10
+ before_save :calculate_responses_text, if: :responses_column_changed?
11
+
12
+ scope :order_by_response_field_value, -> (response_field, direction) {
13
+ if response_field.sort_as_numeric
14
+ order("(responses -> '#{response_field.id}_sortable_value') ::numeric #{direction} NULLS LAST")
15
+ else
16
+ order("LOWER(responses -> '#{response_field.id}_sortable_value') #{direction} NULLS LAST")
17
+ end
18
+ }
19
+
20
+ scope :order_by_response_field_checkbox_value, -> (response_field, option, direction) {
21
+ order("(CASE WHEN (responses -> '#{response_field.id}_sortable_values_#{option}') = 'true' THEN
22
+ 1
23
+ ELSE
24
+ 0
25
+ END) #{direction}".squish)
26
+ }
27
+
28
+ scope :order_by_response_field_table_sum, -> (response_field, column, direction) {
29
+ order("(responses -> '#{response_field.id}_sum_#{column}') ::numeric #{direction}")
30
+ }
31
+ end
32
+
33
+ def valid_page?(x)
34
+ self.valid?
35
+ !self.errors_on_page?(x)
36
+ end
37
+
38
+ def first_page_with_errors
39
+ if (i = pages_with_errors.find_index { |x| x == true })
40
+ i + 1
41
+ else
42
+ nil
43
+ end
44
+ end
45
+
46
+ def pages_with_errors
47
+ form.response_fields_by_page.map do |page|
48
+ page.find { |response_field| self.error_for(response_field).present? } ? true : false
49
+ end
50
+ end
51
+
52
+ def errors_on_page?(x)
53
+ pages_with_errors[x - 1] # 0-indexed
54
+ end
55
+
56
+ def responses_column
57
+ @responses_column || 'responses'
58
+ end
59
+
60
+ def responses_column=(x)
61
+ @responses_column = x
11
62
  end
12
63
 
13
- def submit!(skip_validation = false)
14
- return false if !skip_validation && !valid?
64
+ def get_responses
65
+ send(responses_column)
66
+ end
15
67
 
16
- self.audit_responses
68
+ def set_responses(x)
69
+ send("#{responses_column}=", x)
70
+ end
17
71
 
18
- self.update_attributes(
19
- submitted_at: Time.now,
20
- skip_validation: true # don't validate twice
21
- )
72
+ def mark_responses_as_changed!
73
+ send("#{responses_column}_will_change!")
22
74
  end
23
75
 
24
- def unsubmit!
25
- self.update_attributes(
26
- submitted_at: nil,
27
- skip_validation: true
28
- )
76
+ def responses_column_changed?
77
+ send("#{responses_column}_changed?")
29
78
  end
30
79
 
31
- def submitted?
32
- self.submitted_at.present?
80
+ def responses_column_was
81
+ send("#{responses_column}_was")
33
82
  end
34
83
 
35
84
  def value_present?(response_field)
@@ -49,13 +98,8 @@ module Formbuilder
49
98
  return false
50
99
  end
51
100
 
52
- # checkboxes can have no values, yet still need to show up as unchecked
53
- def value_present_or_checkboxes?(response_field)
54
- response_field.field_type == 'checkboxes' || value_present?(response_field)
55
- end
56
-
57
101
  def response_value(response_field)
58
- value = responses && responses[response_field.id.to_s]
102
+ value = get_responses[response_field.id.to_s]
59
103
 
60
104
  if value
61
105
  response_field.serialized ? YAML::load(value) : value
@@ -66,176 +110,75 @@ module Formbuilder
66
110
  end
67
111
  end
68
112
 
69
- def save_responses(response_field_params, response_fields)
70
- self.old_responses = self.responses.try(:clone) || {}
71
- self.responses = {}
113
+ def save_responses(response_field_params, response_fields, opts = {})
114
+ set_responses({}) unless opts[:partial_update]
72
115
 
73
- response_fields.reject { |rf| !rf.input_field }.each do |response_field|
74
- self.save_response(response_field_params.try(:[], response_field.id.to_s), response_field, response_field_params)
116
+ response_fields.select { |rf| rf.input_field }.each do |response_field|
117
+ self.save_response(response_field_params[response_field.id.to_s], response_field, response_field_params)
75
118
  end
76
119
  end
77
120
 
78
121
  def save_response(raw_value, response_field, response_field_params = {})
79
- value = case response_field.field_type
80
- when "checkboxes"
81
- # transform checkboxes into {label => on/off} pairs
82
- values = {}
83
-
84
- (response_field[:field_options]["options"] || []).each_with_index do |option, index|
85
- label = response_field.field_options["options"][index]["label"]
86
- values[option["label"]] = raw_value && raw_value[index.to_s] == "on"
87
- end
88
-
89
- if raw_value && raw_value['other_checkbox'] == 'on'
90
- values['Other'] = raw_value['other']
91
- else
92
- values.delete('Other') # @todo this might cause unexpected behavior to the user. we should hide/show the other field in the frontend, too
93
- end
94
-
95
- # Save 'other' value
96
- responses["#{response_field.id}_other"] = raw_value && raw_value['other_checkbox'] == 'on' ?
97
- true :
98
- nil
99
-
100
- values
101
-
102
- when "file"
103
- # if the file is already uploaded and we're not uploading another,
104
- # be sure to keep it
105
- if raw_value.blank?
106
- if old_responses && old_responses[response_field.id.to_s]
107
- old_responses[response_field.id.to_s]
108
- end
109
- else
110
- remove_entry_attachment(responses[response_field.id.to_s]) if responses
111
- attachment = EntryAttachment.create(upload: raw_value)
112
- attachment.id
113
- end
114
- when "radio"
115
- # Save 'other' value
116
- responses["#{response_field.id}_other"] = raw_value == 'Other' ?
117
- response_field_params["#{response_field.id}_other"] :
118
- nil
119
-
120
- raw_value
121
- else
122
- raw_value
123
- end
124
-
125
- self.responses ||= {}
122
+ value = response_field.transform_raw_value(raw_value, self, response_field_params: response_field_params)
126
123
 
127
124
  if value.present?
128
- self.responses["#{response_field.id}"] = response_field.serialized ? value.to_yaml : value
129
- calculate_sortable_value(response_field, value)
125
+ get_responses["#{response_field.id}"] = response_field.serialized ? value.to_yaml : value
126
+ get_responses["#{response_field.id}_sortable_value"] = response_field.sortable_value(value)
127
+ else
128
+ get_responses.delete("#{response_field.id}")
129
+ get_responses.delete("#{response_field.id}_sortable_value")
130
130
  end
131
131
 
132
- self.responses_will_change! # hack to make sure column is marked as dirty
132
+ mark_responses_as_changed!
133
133
  end
134
134
 
135
135
  def destroy_response(response_field)
136
- case response_field.field_type
137
- when "file"
138
- self.remove_entry_attachment(responses[response_field.id.to_s])
139
- end
140
-
136
+ response_field.before_response_destroyed(self)
141
137
  id = response_field.id.to_s
142
- new_responses = self.responses.reject { |k, v| k.in?([id, "#{id}_sortable_value"]) }
143
- self.responses = new_responses
144
-
145
- self.responses_will_change! # hack to make sure column is marked as dirty
146
- end
147
-
148
- def remove_entry_attachment(entry_attachment_id)
149
- return unless entry_attachment_id.present?
150
- EntryAttachment.where(id: entry_attachment_id).first.try(:destroy)
138
+ set_responses get_responses.reject { |k, v| k.in?([id, "#{id}_sortable_value"]) }
139
+ mark_responses_as_changed!
151
140
  end
152
141
 
153
142
  def error_for(response_field)
154
- (self.errors.messages[:"responses_#{response_field.id}"] || [])[0]
143
+ Array(self.errors.messages[:"#{responses_column}_#{response_field.id}"]).first
155
144
  end
156
145
 
157
146
  def calculate_responses_text
158
- return unless self.respond_to?(:"responses_text=")
159
- selected_responses = self.responses.select { |k, v| Integer(k) rescue nil }
160
- self.responses_text = selected_responses.values.join(' ')
147
+ return unless self.respond_to?(:"#{responses_column}_text=")
148
+ self.send(:"#{responses_column}_text=", get_responses.select { |k, v| Integer(k) rescue nil }.values.join(' '))
161
149
  end
162
150
 
163
- # useful when migrating
151
+ # for manual use, maybe when migrating
164
152
  def calculate_sortable_values
165
- response_fieldable.response_fields.reject { |rf| !rf.input_field }.each do |response_field|
166
- calculate_sortable_value(response_field, response_value(response_field))
153
+ response_fieldable.input_fields.each do |response_field|
154
+ if (x = response_value(response_field)).present?
155
+ get_responses["#{response_field.id}_sortable_value"] = response_field.sortable_value(x)
156
+ end
167
157
  end
168
158
 
169
- self.responses_will_change! # hack to make sure column is marked as dirty
159
+ mark_responses_as_changed!
170
160
  end
171
161
 
172
- def calculate_additional_info
173
- response_fieldable.response_fields.reject { |rf| !rf.input_field }.each do |response_field|
174
- value = response_value(response_field)
175
- next unless value.present?
162
+ # Normalizations get run before validation.
163
+ def normalize_responses
164
+ return if form.blank?
176
165
 
177
- case response_field.field_type
178
- when 'address'
179
- begin
180
- coords = Geocoder.coordinates("#{value['street']} #{value['city']} #{value['state']} #{value['zipcode']} #{value['country']}")
181
- self.responses["#{response_field.id}_x"] = coords[0]
182
- self.responses["#{response_field.id}_y"] = coords[1]
183
- rescue
184
- self.responses["#{response_field.id}_x"] = nil
185
- self.responses["#{response_field.id}_y"] = nil
186
- end
166
+ form.response_fields.each do |response_field|
167
+ if (x = self.response_value(response_field))
168
+ response_field.normalize_response(x, get_responses)
187
169
  end
188
170
  end
189
- end
190
-
191
- # def normalize_responses
192
- # response_fieldable.response_fields.reject { |rf| !rf.input_field }.each do |response_field|
193
- # value = response_value(response_field)
194
- # next unless value.present?
195
171
 
196
- # case response_field.field_type
197
- # when 'website'
198
- # unless value[/^http:\/\//] || value[/^https:\/\//]
199
- # save_response("http://#{value}", response_field)
200
- # end
201
- # end
202
- # end
203
- # end
172
+ mark_responses_as_changed!
173
+ end
204
174
 
175
+ # Audits get run explicitly.
205
176
  def audit_responses
206
177
  form.response_fields.each do |response_field|
207
- response_field.audit_response(self.response_value(response_field), self.responses)
178
+ response_field.audit_response(self.response_value(response_field), get_responses)
208
179
  end
209
- end
210
180
 
211
- def calculate_sortable_value(response_field, value)
212
- return unless value.present?
213
-
214
- self.responses["#{response_field.id}_sortable_value"] = case response_field.field_type
215
- when "date"
216
- ['year', 'month', 'day'].each { |x| return 0 unless value[x] && !value[x].blank? }
217
- DateTime.new(value['year'].to_i, value['month'].to_i, value['day'].to_i).to_i rescue 0
218
- when "time"
219
- hours = value['hours'].to_i
220
- hours += 12 if value['am_pm'] && value['am_pm'] == 'PM'
221
- (hours*60*60) + (value['minutes'].to_i * 60) + value['seconds'].to_i
222
- when "file"
223
- value ? 1 : 0
224
- when "checkboxes"
225
- calculate_sortable_value_for_checkboxes(response_field, value)
226
- return nil
227
- when "price"
228
- "#{value['dollars'] || '0'}.#{value['cents'] || '0'}".to_f
229
- else
230
- # do we really need to sort more than the first 10 characters of a string?
231
- value[0..10]
232
- end
233
- end
234
-
235
- def calculate_sortable_value_for_checkboxes(response_field, value)
236
- (response_field.field_options['options'] || []).each do |option|
237
- self.responses["#{response_field.id}_sortable_values_#{option['label']}"] = value[option['label']]
238
- end
181
+ mark_responses_as_changed!
239
182
  end
240
183
 
241
184
  end
@@ -6,15 +6,22 @@ module Formbuilder
6
6
  @record = record
7
7
 
8
8
  # I guess it's valid if there's no form?
9
- return unless record.form
10
-
11
- # It's also valid if it has already been submitted
12
- return if record.submitted_at_was
9
+ return if record.form.blank?
13
10
 
14
11
  # we can also skip validation by setting this flag
15
12
  return if record.skip_validation
16
13
 
17
- record.form.response_fields.not_admin_only.reject { |rf| !rf.input_field }.each do |response_field|
14
+ record.form.show_blind = true
15
+
16
+ if record.only_validate_page
17
+ query = record.form.response_fields_for_page(record.only_validate_page)
18
+ else
19
+ query = record.form.filtered_response_fields
20
+ end
21
+
22
+ query = query.reject { |rf| !rf.input_field }
23
+
24
+ query.each do |response_field|
18
25
  @response_field = response_field
19
26
  @value = @record.response_value(@response_field)
20
27
 
@@ -37,7 +44,7 @@ module Formbuilder
37
44
  private
38
45
  def add_error(msg)
39
46
  return unless msg.present?
40
- @record.errors["responses_#{@response_field.id}"] << msg
47
+ @record.errors["#{@record.responses_column}_#{@response_field.id}"] << msg
41
48
  end
42
49
 
43
50
  def run_validation(method_name)