client_side_validations 3.0.4 → 3.0.5

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 (53) hide show
  1. data/client_side_validations.gemspec +2 -3
  2. data/javascript/rails.validations.js +26 -12
  3. data/lib/client_side_validations.rb +2 -0
  4. data/lib/client_side_validations/action_view/form_builder.rb +55 -5
  5. data/lib/client_side_validations/action_view/form_helper.rb +20 -2
  6. data/lib/client_side_validations/active_model.rb +22 -13
  7. data/lib/client_side_validations/active_model/length.rb +12 -10
  8. data/lib/client_side_validations/active_model/numericality.rb +14 -9
  9. data/lib/client_side_validations/active_record/middleware.rb +5 -1
  10. data/lib/client_side_validations/active_record/uniqueness.rb +10 -8
  11. data/lib/client_side_validations/middleware.rb +2 -0
  12. data/lib/client_side_validations/mongo_mapper.rb +9 -0
  13. data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
  14. data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
  15. data/lib/client_side_validations/mongoid/uniqueness.rb +10 -8
  16. data/lib/client_side_validations/version.rb +1 -1
  17. data/test/action_view/cases/helper.rb +7 -1
  18. data/test/action_view/cases/test_helpers.rb +263 -0
  19. data/test/action_view/cases/test_legacy_helpers.rb +11 -0
  20. data/test/active_model/cases/test_validations.rb +21 -8
  21. data/test/active_record/cases/test_middleware.rb +25 -0
  22. data/test/active_record/cases/test_uniqueness_validator.rb +5 -0
  23. data/test/active_record/models/user.rb +4 -0
  24. data/test/formtastic/cases/test_form_helper.rb +1 -1
  25. data/test/javascript/public/test/callbacks/elementAfter.js +1 -1
  26. data/test/javascript/public/test/callbacks/elementBefore.js +1 -1
  27. data/test/javascript/public/test/callbacks/elementFail.js +1 -1
  28. data/test/javascript/public/test/callbacks/elementPass.js +1 -1
  29. data/test/javascript/public/test/callbacks/formAfter.js +1 -1
  30. data/test/javascript/public/test/callbacks/formBefore.js +1 -1
  31. data/test/javascript/public/test/callbacks/formFail.js +1 -1
  32. data/test/javascript/public/test/callbacks/formPass.js +1 -1
  33. data/test/javascript/public/test/form_builders/validateForm.js +1 -1
  34. data/test/javascript/public/test/form_builders/validateFormtastic.js +1 -1
  35. data/test/javascript/public/test/form_builders/validateNestedForm.js +66 -0
  36. data/test/javascript/public/test/form_builders/validateSimpleForm.js +1 -1
  37. data/test/javascript/public/test/validateElement.js +36 -1
  38. data/test/javascript/public/test/validators/length.js +7 -1
  39. data/test/javascript/public/test/validators/numericality.js +7 -0
  40. data/test/javascript/public/test/validators/presence.js +6 -0
  41. data/test/javascript/public/test/validators/uniqueness.js +8 -1
  42. data/test/javascript/server.rb +7 -1
  43. data/test/javascript/views/index.erb +1 -1
  44. data/test/mongo_mapper/cases/helper.rb +9 -0
  45. data/test/mongo_mapper/cases/test_base.rb +15 -0
  46. data/test/mongo_mapper/cases/test_middleware.rb +77 -0
  47. data/test/mongo_mapper/cases/test_uniqueness_validator.rb +50 -0
  48. data/test/mongo_mapper/models/magazine.rb +11 -0
  49. data/test/mongoid/cases/test_middleware.rb +9 -0
  50. data/test/mongoid/cases/test_uniqueness_validator.rb +5 -0
  51. data/test/mongoid/models/book.rb +4 -0
  52. data/test/simple_form/cases/test_form_helper.rb +1 -1
  53. metadata +46 -20
@@ -12,19 +12,18 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{Client Side Validations}
13
13
  s.description = %q{Client Side Validations}
14
14
 
15
- s.rubyforge_project = "client_side_validations"
16
-
17
15
  s.files = `git ls-files -- {lib/*,javascript/*,*.gemspec}`.split("\n")
18
16
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
17
  s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
18
  s.require_paths = ["lib"]
21
19
 
22
- s.add_dependency 'activesupport', '~> 3.0.0'
20
+ s.add_dependency 'activesupport'
23
21
 
24
22
  s.add_development_dependency 'rails', '~> 3.0.0'
25
23
  s.add_development_dependency 'sqlite3'
26
24
  s.add_development_dependency 'bson_ext'
27
25
  s.add_development_dependency 'mongoid', '~> 2.0.0'
26
+ s.add_development_dependency 'mongo_mapper','~>0.9.0'
28
27
  s.add_development_dependency 'mocha'
29
28
  s.add_development_dependency 'simple_form'
30
29
  s.add_development_dependency 'formtastic'
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Rails 3 Client Side Validations - v3.0.1
2
+ * Rails 3 Client Side Validations - v3.0.5
3
3
  * https://github.com/bcardarlela/client_side_validations
4
4
  *
5
5
  * Copyright (c) 2011 Brian Cardarella
@@ -48,13 +48,15 @@
48
48
  var confirmationElement = $(this),
49
49
  element = form.find('#' + this.id.match(/(.+)_confirmation/)[1] + '[data-validate]:input');
50
50
 
51
- $('#' + confirmationElement.attr('id'))
52
- .live('focusout', function() {
53
- element.data('changed', true).isValid(settings.validators);
54
- })
55
- .live('keyup', function() {
56
- element.data('changed', true).isValid(settings.validators);
57
- })
51
+ if (element[0]) {
52
+ $('#' + confirmationElement.attr('id'))
53
+ .live('focusout', function() {
54
+ element.data('changed', true).isValid(settings.validators);
55
+ })
56
+ .live('keyup', function() {
57
+ element.data('changed', true).isValid(settings.validators);
58
+ })
59
+ }
58
60
  });
59
61
 
60
62
  var addError = function(element, message) {
@@ -127,7 +129,7 @@ var clientSideValidations = {
127
129
  all: function() { return jQuery.extend({}, clientSideValidations.validators.local, clientSideValidations.validators.remote) },
128
130
  local: {
129
131
  presence: function(element, options) {
130
- if (/^\s*$/.test(element.val())) {
132
+ if (/^\s*$/.test(element.val() || "")) {
131
133
  return options.message;
132
134
  }
133
135
  },
@@ -171,7 +173,7 @@ var clientSideValidations = {
171
173
  equal_to: '==', less_than: '<', less_than_or_equal_to: '<=' }
172
174
 
173
175
  for (var check in CHECKS) {
174
- if (options[check] && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
176
+ if (options[check] != undefined && !(new Function("return " + element.val() + CHECKS[check] + options[check])())) {
175
177
  return options.messages[check];
176
178
  }
177
179
  }
@@ -191,7 +193,7 @@ var clientSideValidations = {
191
193
  } else if (options.minimum) {
192
194
  blankOptions.message = options.messages.minimum;
193
195
  }
194
- if ((message = this.presence(element, blankOptions)) && options.allow_blank == true && !options.maximum) {
196
+ if ((message = this.presence(element, blankOptions)) && options.allow_blank == true) {
195
197
  return;
196
198
  } else if (message) {
197
199
  return message;
@@ -290,6 +292,11 @@ var clientSideValidations = {
290
292
  } else {
291
293
  var name = element.attr('name');
292
294
  }
295
+
296
+ // Override the name if a nested module class is passed
297
+ if (options['class']) {
298
+ name = options['class'] + '[' + name.split('[')[1]
299
+ }
293
300
  data[name] = element.val();
294
301
 
295
302
  if (jQuery.ajax({
@@ -370,7 +377,14 @@ var clientSideValidations = {
370
377
  var errorElement = wrapper.find('p.' + settings.inline_error_class);
371
378
  errorElement.remove();
372
379
  }
373
-
380
+ },
381
+ 'NestedForm::Builder': {
382
+ add: function(element, settings, message) {
383
+ clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].add(element, settings, message);
384
+ },
385
+ remove: function(element, settings, message) {
386
+ clientSideValidations.formBuilders['ActionView::Helpers::FormBuilder'].remove(element, settings, message);
387
+ }
374
388
  }
375
389
  },
376
390
  callbacks: {
@@ -1,8 +1,10 @@
1
1
  module ClientSideValidations
2
2
  end
3
3
 
4
+ require 'client_side_validations/active_model' if defined?(::ActiveModel)
4
5
  require 'client_side_validations/active_record' if defined?(::ActiveRecord)
5
6
  require 'client_side_validations/mongoid' if defined?(::Mongoid)
7
+ require 'client_side_validations/mongo_mapper' if defined?(::MongoMapper)
6
8
  require 'client_side_validations/action_view'
7
9
  require 'client_side_validations/middleware' if defined?(::Rails)
8
10
 
@@ -27,7 +27,7 @@ module ClientSideValidations::ActionView::Helpers
27
27
  def self.client_side_form_settings(options, form_helper)
28
28
  {
29
29
  :type => self.to_s,
30
- :input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />}, Struct.new(:error_message, :tag_id).new([], "")),
30
+ :input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />}, Struct.new(:error_message, :tag_id).new([], "")),
31
31
  :label_tag => form_helper.class.field_error_proc.call(%{<label id="label_tag" />}, Struct.new(:error_message, :tag_id).new([], ""))
32
32
  }
33
33
  end
@@ -80,17 +80,27 @@ module ClientSideValidations::ActionView::Helpers
80
80
  def apply_client_side_validators(method, options = {})
81
81
  if @options[:validate] && options[:validate] != false && validators = filter_validators(@object.client_side_validation_hash[method], options[:validate])
82
82
  options.merge!("data-validate" => true)
83
- @options[:validators].merge!("#{@object_name}[#{method}]" => validators)
83
+ @options[:validators].merge!("#{@object_name}[#{method}]#{options[:multiple] ? "[]" : nil}" => validators)
84
84
  end
85
85
  end
86
86
 
87
87
  def filter_validators(validators, filters)
88
88
  if validators
89
89
  filtered_validators = validators.inject({}) do |filtered_validators, validator|
90
- unless filters && filters.key?(validator.first) && !filters[validator.first]
91
- filtered_validators[validator.first] = validator.last
90
+ filtered_validators[validator.first] = validator.last
91
+ if has_filter_for_validator?(validator, filters)
92
+ if filter_validator?(validator, filters)
93
+ filtered_validators.delete(validator.first)
94
+ elsif force_validator_despite_conditional?(validator, filters) && !can_run_validator?(validator)
95
+ filtered_validators.delete(validator.first)
96
+ end
97
+ else
98
+ if validator.last.key?(:if) || validator.last.key?(:unless)
99
+ filtered_validators.delete(validator.first)
100
+ end
92
101
  end
93
-
102
+ filtered_validators[validator.first].delete(:if) if filtered_validators[validator.first]
103
+ filtered_validators[validator.first].delete(:unless) if filtered_validators[validator.first]
94
104
  filtered_validators
95
105
  end
96
106
 
@@ -98,5 +108,45 @@ module ClientSideValidations::ActionView::Helpers
98
108
  end
99
109
  end
100
110
 
111
+ def has_filter_for_validator?(validator, filters)
112
+ filters && (filters == true || filters.key?(validator.first))
113
+ end
114
+
115
+ def filter_validator?(validator, filters)
116
+ filters != true && filters[validator.first] == false
117
+ end
118
+
119
+ def force_validator_despite_conditional?(validator, filters)
120
+ filters == true || filters[validator.first] == true
121
+ end
122
+
123
+ def can_run_validator?(validator)
124
+ result = true
125
+ if_result = can_run_if_validator?(validator.last[:if])
126
+ unless_result = can_run_unless_validator?(validator.last[:unless])
127
+ result = result && if_result unless if_result.nil?
128
+ result = result && unless_result unless unless_result.nil?
129
+ result
130
+ end
131
+
132
+ def can_run_if_validator?(conditional)
133
+ if conditional
134
+ if conditional.is_a?(Symbol)
135
+ !!@object.send(conditional)
136
+ else
137
+ !!conditional.call(@object)
138
+ end
139
+ end
140
+ end
141
+
142
+ def can_run_unless_validator?(conditional)
143
+ if conditional
144
+ if conditional.is_a?(Symbol)
145
+ !@object.send(conditional)
146
+ else
147
+ !conditional.call(@object)
148
+ end
149
+ end
150
+ end
101
151
  end
102
152
  end
@@ -6,6 +6,8 @@ module ClientSideValidations::ActionView::Helpers
6
6
  options = args.extract_options!
7
7
  if options[:validate]
8
8
 
9
+ content_for_name = options[:validate] unless options[:validate] == true
10
+
9
11
  # Always turn off HTML5 Validations
10
12
  options[:html] ||= {}
11
13
  options[:html][:novalidate] = true
@@ -26,7 +28,12 @@ module ClientSideValidations::ActionView::Helpers
26
28
  form = super(record_or_name_or_array, *(args << options), &proc)
27
29
  # Because of the load order requirement above this sub is necessary
28
30
  # Would be nice to not do this
29
- "#{form}#{script ? script.sub('"validator_hash"', @validators.to_json) : nil}".html_safe
31
+ script = insert_validators_into_script(script)
32
+ if content_for_name
33
+ content_for(content_for_name) { script.html_safe }
34
+ script = nil
35
+ end
36
+ "#{form}#{script}".html_safe
30
37
  end
31
38
 
32
39
  def apply_form_for_options!(object_or_array, options)
@@ -42,6 +49,17 @@ module ClientSideValidations::ActionView::Helpers
42
49
 
43
50
  private
44
51
 
52
+ def insert_validators_into_script(script)
53
+ # There is probably a more performant way of doing this
54
+ # But using String#sub has some issues. Undocumented "features"
55
+ if script
56
+ script = script.split(/"validator_hash"/)
57
+ script = "#{script[0]}#{@validators.to_json}#{script[1]}"
58
+ end
59
+
60
+ script
61
+ end
62
+
45
63
  def client_side_form_settings(object, options)
46
64
  if options[:validate]
47
65
  builder = options[:builder] || ActionView::Base.default_form_builder
@@ -57,7 +75,7 @@ module ClientSideValidations::ActionView::Helpers
57
75
  end
58
76
 
59
77
  content_tag(:script) do
60
- "var #{var_name} = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};".html_safe
78
+ "window['#{var_name}'] = #{builder.client_side_form_settings(options, self).merge(:validators => 'validator_hash').to_json};".html_safe
61
79
  end
62
80
 
63
81
  end
@@ -4,8 +4,9 @@ module ClientSideValidations::ActiveModel
4
4
  module Validator
5
5
 
6
6
  def client_side_hash(model, attribute)
7
- extra_options = options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:on, :allow_blank])
8
- { :message => model.errors.generate_message(attribute, message_type, extra_options) }.merge(extra_options)
7
+ options = self.options.dup
8
+ { :message => model.errors.generate_message(attribute, message_type, options) }.
9
+ merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
9
10
  end
10
11
 
11
12
  private
@@ -17,26 +18,34 @@ module ClientSideValidations::ActiveModel
17
18
 
18
19
  module Validations
19
20
  def client_side_validation_hash
20
- _validators.except(nil, :block).inject({}) do |attr_hash, attr|
21
+ @client_side_validation_hash ||= _validators.inject({}) do |attr_hash, attr|
22
+ unless [nil, :block].include?(attr[0])
23
+
24
+ validator_hash = attr[1].inject({}) do |kind_hash, validator|
25
+ client_side_hash = validator.client_side_hash(self, attr[0])
26
+ # Yeah yeah, #new_record? is not part of ActiveModel :p
27
+ if (can_use_for_client_side_validation?(client_side_hash, validator))
28
+ kind_hash.merge!(validator.kind => client_side_hash.except(:on))
29
+ else
30
+ kind_hash.merge!({})
31
+ end
32
+ end
21
33
 
22
- validator_hash = attr[1].inject({}) do |kind_hash, validator|
23
- client_side_hash = validator.client_side_hash(self, attr[0])
24
- # Yeah yeah, #new_record? is not part of ActiveModel :p
25
- if (can_use_for_client_side_validation?(client_side_hash, validator))
26
- kind_hash.merge!(validator.kind => client_side_hash.except(:on))
34
+ if validator_hash.present?
35
+ attr_hash.merge!(attr[0] => validator_hash)
27
36
  else
28
- kind_hash.merge!({})
37
+ attr_hash
29
38
  end
39
+ else
40
+ attr_hash
30
41
  end
31
-
32
- attr_hash.merge!(attr[0] => validator_hash)
33
- end.delete_if { |key, value| value.blank? }
42
+ end
34
43
  end
35
44
 
36
45
  private
37
46
 
38
47
  def can_use_for_client_side_validation?(client_side_hash, validator)
39
- ((self.respond_to?(:new_record?) && client_side_hash[:on] == (self.new_record? ? :create : :update)) || client_side_hash[:on].nil?) && !validator.options.key?(:if) && !validator.options.key?(:unless) && validator.kind != :block
48
+ ((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?) && validator.kind != :block
40
49
  end
41
50
  end
42
51
  end
@@ -2,19 +2,21 @@ module ClientSideValidations::ActiveModel
2
2
  module Length
3
3
 
4
4
  def client_side_hash(model, attribute)
5
- extra_options = options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :on]).except(:tokenizer, :too_long, :too_short, :wrong_length)
5
+ options = self.options.dup
6
+ hash = { :messages => {} }
7
+ hash[:js_tokenizer] = options[:js_tokenizer] if options[:js_tokenizer]
8
+ hash[:allow_blank] = true if options[:allow_blank]
6
9
 
7
- errors_options = options.except(*self.class::RESERVED_OPTIONS)
8
- messages = extra_options.except(:js_tokenizer, :allow_blank, :on).keys.inject({}) do |hash, key|
9
- errors_options[:count] = extra_options[key]
10
- count = extra_options[key]
11
- default_message = options[self.class::MESSAGES[key]]
12
- errors_options[:message] ||= default_message if default_message
13
-
14
- hash.merge!(key => model.errors.generate_message(attribute, self.class::MESSAGES[key], errors_options))
10
+ self.class::MESSAGES.each do |option, message_type|
11
+ if count = options[option]
12
+ options[:message] = options[message_type]
13
+ options.delete(:message) if options[:message].nil?
14
+ hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
15
+ hash[option] = count
16
+ end
15
17
  end
16
18
 
17
- { :messages => messages }.merge(extra_options)
19
+ hash
18
20
  end
19
21
 
20
22
  end
@@ -5,20 +5,25 @@ module ClientSideValidations::ActiveModel
5
5
 
6
6
  def self.included(base)
7
7
  OPTION_MAP.merge!(base::CHECKS.keys.inject({}) { |hash, key| hash.merge!(key => key) })
8
- OPTION_MAP.merge!(:numericality => :not_a_number, :only_integer => :not_an_integer)
9
8
  end
10
9
 
11
10
  def client_side_hash(model, attribute)
12
- except_options = ::ActiveModel::Errors::CALLBACKS_OPTIONS - [:on] + [:message]
13
- extra_options = options.except(*except_options).reject { |key, value| key == :only_integer && !value }
14
- keys = [:numericality] | (extra_options.keys - [:message, :on])
15
- filtered_options = options.except(*self.class::RESERVED_OPTIONS)
16
- messages = keys.inject({}) do |hash, key|
17
- count = extra_options[key]
18
- hash.merge!(key => model.errors.generate_message(attribute, OPTION_MAP[key], filtered_options.merge(:count => count)))
11
+ options = self.options.dup
12
+ hash = { :messages => { :numericality => model.errors.generate_message(attribute, :not_a_number, options) } }
13
+
14
+ if options[:only_integer]
15
+ hash[:messages][:only_integer] = model.errors.generate_message(attribute, :not_an_integer, options)
16
+ hash[:only_integer] = true
17
+ end
18
+
19
+ OPTION_MAP.each do |option, message_type|
20
+ if count = options[option]
21
+ hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
22
+ hash[option] = count
23
+ end
19
24
  end
20
25
 
21
- { :messages => messages }.merge(extra_options)
26
+ hash
22
27
  end
23
28
 
24
29
  end
@@ -17,7 +17,11 @@ module ClientSideValidations::ActiveRecord
17
17
  relation = t[attribute].matches(value)
18
18
  end
19
19
 
20
- relation = relation.and(t.primary_key.not_eq(params[:id])) if params[:id]
20
+ if relation.is_a?(Arel::Nodes::SqlLiteral)
21
+ relation = Arel::Nodes::SqlLiteral.new("BINARY #{t[attribute].eq(value).to_sql} AND #{t.primary_key.not_eq(params[:id]).to_sql}")
22
+ else
23
+ relation = relation.and(t.primary_key.not_eq(params[:id])) if params[:id]
24
+ end
21
25
 
22
26
  (params[:scope] || {}).each do |key, value|
23
27
  relation = relation.and(t[key].eq(value))
@@ -1,16 +1,18 @@
1
1
  module ClientSideValidations::ActiveRecord
2
2
  module Uniqueness
3
3
  def client_side_hash(model, attribute)
4
- extra_options = options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:on, :allow_blank])
5
- hash = { :message => model.errors.generate_message(attribute, message_type, extra_options.except(:case_sensitive, :scope)) }
6
- hash = hash.merge(extra_options).merge(model.new_record? ? {} : { :id => model.id })
7
-
8
- if hash[:scope].present?
9
- hash[:scope] = Array.wrap(hash[:scope]).inject({}) do |scope_hash, scope_item|
4
+ hash = {}
5
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
6
+ hash[:case_sensitive] = options[:case_sensitive]
7
+ hash[:id] = model.id unless model.new_record?
8
+ if options.key?(:scope) && options[:scope].present?
9
+ hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
10
10
  scope_hash.merge!(scope_item => model.send(scope_item))
11
11
  end
12
- else
13
- hash.delete(:scope)
12
+ end
13
+
14
+ unless model.class.name.demodulize == model.class.name
15
+ hash[:class] = model.class.name.underscore
14
16
  end
15
17
 
16
18
  hash
@@ -63,6 +63,8 @@ module ClientSideValidations
63
63
  middleware_klass = ClientSideValidations::ActiveRecord::Middleware
64
64
  elsif (defined?(::Mongoid::Document) && klass.included_modules.include?(::Mongoid::Document))
65
65
  middleware_klass = ClientSideValidations::Mongoid::Middleware
66
+ elsif (defined?(::MongoMapper::Document) && klass.included_modules.include?(::MongoMapper::Document))
67
+ middleware_klass = ClientSideValidations::MongoMapper::Middleware
66
68
  end
67
69
 
68
70
  middleware_klass.is_unique?(klass, attribute, value, request.params)
@@ -0,0 +1,9 @@
1
+ require 'client_side_validations/active_model'
2
+ require 'client_side_validations/mongo_mapper/middleware'
3
+
4
+ %w{uniqueness}.each do |validator|
5
+ require "client_side_validations/mongo_mapper/#{validator}"
6
+ validator.capitalize!
7
+ eval "MongoMapper::Plugins::Validations::#{validator}Validator.send(:include, ClientSideValidations::MongoMapper::#{validator})"
8
+ end
9
+
@@ -0,0 +1,20 @@
1
+ module ClientSideValidations::MongoMapper
2
+ class Middleware
3
+
4
+ # Still need to handle embedded documents
5
+ def self.is_unique?(klass, attribute, value, params)
6
+ if params[:case_sensitive] == 'false'
7
+ value = Regexp.new("^#{Regexp.escape(value.to_s)}$", Regexp::IGNORECASE)
8
+ end
9
+
10
+ criteria = klass.where(attribute => value)
11
+ criteria = criteria.where(:_id => {'$ne' => BSON::ObjectId(params[:id])}) if params[:id]
12
+
13
+ (params[:scope] || {}).each do |key, value|
14
+ criteria = criteria.where(key => value)
15
+ end
16
+
17
+ !criteria.exists?
18
+ end
19
+ end
20
+ end