client_side_validations 3.0.3 → 3.1.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.
- data/client_side_validations.gemspec +4 -7
- data/lib/client_side_validations/action_view/form_builder.rb +85 -11
- data/lib/client_side_validations/action_view/form_helper.rb +21 -3
- data/lib/client_side_validations/action_view.rb +4 -3
- data/lib/client_side_validations/active_model/length.rb +12 -10
- data/lib/client_side_validations/active_model/numericality.rb +14 -9
- data/lib/client_side_validations/active_model.rb +21 -13
- data/lib/client_side_validations/active_record/middleware.rb +5 -1
- data/lib/client_side_validations/active_record/uniqueness.rb +10 -8
- data/lib/client_side_validations/engine.rb +6 -0
- data/lib/client_side_validations/files.rb +8 -0
- data/lib/client_side_validations/formtastic.rb +3 -3
- data/lib/client_side_validations/middleware.rb +5 -7
- data/lib/client_side_validations/mongo_mapper/middleware.rb +20 -0
- data/lib/client_side_validations/mongo_mapper/uniqueness.rb +28 -0
- data/lib/client_side_validations/mongo_mapper.rb +9 -0
- data/lib/client_side_validations/mongoid/uniqueness.rb +10 -8
- data/lib/client_side_validations/version.rb +1 -1
- data/lib/client_side_validations.rb +8 -3
- data/lib/generators/client_side_validations/copy_asset_generator.rb +23 -0
- data/lib/generators/client_side_validations/install_generator.rb +18 -6
- data/lib/generators/templates/client_side_validations/README.rails.3.0 +6 -0
- data/lib/generators/templates/client_side_validations/README.rails.3.1 +7 -0
- data/lib/generators/templates/{client_side_validations.rb → client_side_validations/initializer.rb} +1 -1
- data/test/action_view/cases/helper.rb +34 -12
- data/test/action_view/cases/test_helpers.rb +314 -1
- data/test/action_view/cases/test_legacy_helpers.rb +58 -1
- data/test/active_model/cases/test_validations.rb +21 -8
- data/test/active_record/cases/test_middleware.rb +41 -16
- data/test/active_record/cases/test_uniqueness_validator.rb +5 -0
- data/test/active_record/models/user.rb +4 -0
- data/test/base_helper.rb +2 -0
- data/test/core_ext/cases/test_core_ext.rb +1 -0
- data/test/formtastic/cases/helper.rb +5 -0
- data/test/formtastic/cases/test_form_builder.rb +3 -3
- data/test/formtastic/cases/test_form_helper.rb +3 -4
- data/test/generators/cases/test_generators.rb +31 -0
- data/test/javascript/public/test/callbacks/elementAfter.js +1 -1
- data/test/javascript/public/test/callbacks/elementBefore.js +1 -1
- data/test/javascript/public/test/callbacks/elementFail.js +1 -1
- data/test/javascript/public/test/callbacks/elementPass.js +1 -1
- data/test/javascript/public/test/callbacks/formAfter.js +1 -1
- data/test/javascript/public/test/callbacks/formBefore.js +1 -1
- data/test/javascript/public/test/callbacks/formFail.js +1 -1
- data/test/javascript/public/test/callbacks/formPass.js +1 -1
- data/test/javascript/public/test/form_builders/validateForm.js +1 -1
- data/test/javascript/public/test/form_builders/validateFormtastic.js +2 -2
- data/test/javascript/public/test/form_builders/validateNestedForm.js +66 -0
- data/test/javascript/public/test/form_builders/validateSimpleForm.js +1 -1
- data/test/javascript/public/test/validateElement.js +36 -1
- data/test/javascript/public/test/validators/length.js +7 -1
- data/test/javascript/public/test/validators/numericality.js +7 -0
- data/test/javascript/public/test/validators/presence.js +6 -0
- data/test/javascript/public/test/validators/uniqueness.js +8 -1
- data/test/javascript/server.rb +9 -3
- data/test/javascript/views/index.erb +1 -1
- data/test/javascript/views/layout.erb +1 -1
- data/test/middleware/cases/helper.rb +3 -0
- data/test/mongo_mapper/cases/helper.rb +9 -0
- data/test/mongo_mapper/cases/test_base.rb +15 -0
- data/test/mongo_mapper/cases/test_middleware.rb +77 -0
- data/test/mongo_mapper/cases/test_uniqueness_validator.rb +50 -0
- data/test/mongo_mapper/models/magazine.rb +11 -0
- data/test/mongoid/cases/test_middleware.rb +15 -6
- data/test/mongoid/cases/test_uniqueness_validator.rb +5 -0
- data/test/mongoid/models/book.rb +4 -0
- data/test/simple_form/cases/helper.rb +3 -0
- data/test/simple_form/cases/test_form_helper.rb +3 -1
- data/test/test_loader.rb +6 -0
- data/{javascript → vendor/assets/javascripts}/rails.validations.js +32 -17
- metadata +44 -23
- data/lib/generators/templates/README +0 -7
- data/test/generators/cases/test_install_generator.rb +0 -15
|
@@ -12,22 +12,19 @@ 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.
|
|
16
|
-
|
|
17
|
-
s.files = `git ls-files -- {lib/*,javascript/*,*.gemspec}`.split("\n")
|
|
15
|
+
s.files = `git ls-files -- {lib/*,vendor/*,*.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.
|
|
23
|
-
|
|
24
|
-
s.add_development_dependency 'rails', '~> 3.0.0'
|
|
20
|
+
s.add_development_dependency 'rails', '3.1.0.rc4'
|
|
25
21
|
s.add_development_dependency 'sqlite3'
|
|
26
22
|
s.add_development_dependency 'bson_ext'
|
|
27
23
|
s.add_development_dependency 'mongoid', '~> 2.0.0'
|
|
24
|
+
s.add_development_dependency 'mongo_mapper','~>0.9.0'
|
|
28
25
|
s.add_development_dependency 'mocha'
|
|
29
26
|
s.add_development_dependency 'simple_form'
|
|
30
|
-
s.add_development_dependency 'formtastic'
|
|
27
|
+
s.add_development_dependency 'formtastic', '~> 2.0.0.rc3'
|
|
31
28
|
|
|
32
29
|
# For QUnit testing
|
|
33
30
|
s.add_development_dependency 'sinatra', '~> 1.0'
|
|
@@ -2,7 +2,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
|
2
2
|
module FormBuilder
|
|
3
3
|
|
|
4
4
|
def self.included(base)
|
|
5
|
-
(base.field_helpers - %w(apply_form_for_options! label check_box radio_button fields_for hidden_field)).each do |selector|
|
|
5
|
+
(base.field_helpers.map(&:to_s) - %w(apply_form_for_options! label check_box radio_button fields_for hidden_field)).each do |selector|
|
|
6
6
|
base.class_eval <<-RUBY_EVAL
|
|
7
7
|
def #{selector}_with_client_side_validations(method, options = {})
|
|
8
8
|
apply_client_side_validators(method, options)
|
|
@@ -15,16 +15,20 @@ module ClientSideValidations::ActionView::Helpers
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
base.class_eval do
|
|
18
|
-
alias_method_chain :initialize,
|
|
19
|
-
alias_method_chain :fields_for,
|
|
20
|
-
alias_method_chain :check_box,
|
|
21
|
-
alias_method_chain :radio_button,
|
|
18
|
+
alias_method_chain :initialize, :client_side_validations
|
|
19
|
+
alias_method_chain :fields_for, :client_side_validations
|
|
20
|
+
alias_method_chain :check_box, :client_side_validations
|
|
21
|
+
alias_method_chain :radio_button, :client_side_validations
|
|
22
|
+
alias_method_chain :select, :client_side_validations
|
|
23
|
+
alias_method_chain :collection_select, :client_side_validations
|
|
24
|
+
alias_method_chain :grouped_collection_select, :client_side_validations
|
|
25
|
+
alias_method_chain :time_zone_select, :client_side_validations
|
|
22
26
|
|
|
23
27
|
def self.client_side_form_settings(options, form_helper)
|
|
24
28
|
{
|
|
25
29
|
:type => self.to_s,
|
|
26
|
-
:input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />},
|
|
27
|
-
:label_tag => form_helper.class.field_error_proc.call(%{<label id="label_tag" />})
|
|
30
|
+
:input_tag => form_helper.class.field_error_proc.call(%{<span id="input_tag" />}, Struct.new(:error_message, :tag_id).new([], "")),
|
|
31
|
+
:label_tag => form_helper.class.field_error_proc.call(%{<label id="label_tag" />}, Struct.new(:error_message, :tag_id).new([], ""))
|
|
28
32
|
}
|
|
29
33
|
end
|
|
30
34
|
end
|
|
@@ -51,22 +55,52 @@ module ClientSideValidations::ActionView::Helpers
|
|
|
51
55
|
radio_button_without_client_side_validations(method, tag_value, options)
|
|
52
56
|
end
|
|
53
57
|
|
|
58
|
+
def select_with_client_side_validations(method, choices, options = {}, html_options = {})
|
|
59
|
+
apply_client_side_validators(method, html_options)
|
|
60
|
+
select_without_client_side_validations(method, choices, options, html_options)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def collection_select_with_client_side_validations(method, collection, value_method, text_method, options = {}, html_options = {})
|
|
64
|
+
apply_client_side_validators(method, html_options)
|
|
65
|
+
collection_select_without_client_side_validations(method, collection, value_method, text_method, options, html_options)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def grouped_collection_select_with_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
|
|
69
|
+
apply_client_side_validators(method, html_options)
|
|
70
|
+
grouped_collection_select_without_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def time_zone_select_with_client_side_validations(method, priority_zones = nil, options = {}, html_options = {})
|
|
74
|
+
apply_client_side_validators(method, html_options)
|
|
75
|
+
time_zone_select_without_client_side_validations(method, priority_zones = nil, options, html_options)
|
|
76
|
+
end
|
|
77
|
+
|
|
54
78
|
private
|
|
55
79
|
|
|
56
80
|
def apply_client_side_validators(method, options = {})
|
|
57
81
|
if @options[:validate] && options[:validate] != false && validators = filter_validators(@object.client_side_validation_hash[method], options[:validate])
|
|
58
82
|
options.merge!("data-validate" => true)
|
|
59
|
-
@options[:validators].merge!("#{@object_name}[#{method}]" => validators)
|
|
83
|
+
@options[:validators].merge!("#{@object_name}[#{method}]#{options[:multiple] ? "[]" : nil}" => validators)
|
|
60
84
|
end
|
|
61
85
|
end
|
|
62
86
|
|
|
63
87
|
def filter_validators(validators, filters)
|
|
64
88
|
if validators
|
|
65
89
|
filtered_validators = validators.inject({}) do |filtered_validators, validator|
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
68
101
|
end
|
|
69
|
-
|
|
102
|
+
filtered_validators[validator.first].delete(:if) if filtered_validators[validator.first]
|
|
103
|
+
filtered_validators[validator.first].delete(:unless) if filtered_validators[validator.first]
|
|
70
104
|
filtered_validators
|
|
71
105
|
end
|
|
72
106
|
|
|
@@ -74,5 +108,45 @@ module ClientSideValidations::ActionView::Helpers
|
|
|
74
108
|
end
|
|
75
109
|
end
|
|
76
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
|
|
77
151
|
end
|
|
78
152
|
end
|
|
@@ -6,9 +6,11 @@ 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
|
-
options[:html][:novalidate] =
|
|
13
|
+
options[:html][:novalidate] = 'novalidate'
|
|
12
14
|
|
|
13
15
|
case record_or_name_or_array
|
|
14
16
|
when String, Symbol
|
|
@@ -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
|
-
|
|
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
|
-
"
|
|
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
|
|
@@ -3,9 +3,10 @@ module ClientSideValidations::ActionView
|
|
|
3
3
|
end
|
|
4
4
|
end
|
|
5
5
|
|
|
6
|
-
require
|
|
7
|
-
require
|
|
8
|
-
require
|
|
6
|
+
require 'client_side_validations/core_ext'
|
|
7
|
+
require 'client_side_validations/action_view/form_helper'
|
|
8
|
+
require 'client_side_validations/action_view/form_tag_helper'
|
|
9
|
+
require 'client_side_validations/action_view/form_builder'
|
|
9
10
|
|
|
10
11
|
ActionView::Base.send(:include, ClientSideValidations::ActionView::Helpers::FormHelper)
|
|
11
12
|
ActionView::Base.send(:include, ClientSideValidations::ActionView::Helpers::FormTagHelper)
|
|
@@ -2,19 +2,21 @@ module ClientSideValidations::ActiveModel
|
|
|
2
2
|
module Length
|
|
3
3
|
|
|
4
4
|
def client_side_hash(model, attribute)
|
|
5
|
-
|
|
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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
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
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
|
|
26
|
+
hash
|
|
22
27
|
end
|
|
23
28
|
|
|
24
29
|
end
|
|
@@ -4,8 +4,8 @@ module ClientSideValidations::ActiveModel
|
|
|
4
4
|
module Validator
|
|
5
5
|
|
|
6
6
|
def client_side_hash(model, attribute)
|
|
7
|
-
|
|
8
|
-
{ :message => model.errors.generate_message(attribute, message_type,
|
|
7
|
+
options = self.options.dup
|
|
8
|
+
{ :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
private
|
|
@@ -17,26 +17,34 @@ module ClientSideValidations::ActiveModel
|
|
|
17
17
|
|
|
18
18
|
module Validations
|
|
19
19
|
def client_side_validation_hash
|
|
20
|
-
_validators.
|
|
20
|
+
@client_side_validation_hash ||= _validators.inject({}) do |attr_hash, attr|
|
|
21
|
+
unless [nil, :block].include?(attr[0])
|
|
22
|
+
|
|
23
|
+
validator_hash = attr[1].inject({}) do |kind_hash, validator|
|
|
24
|
+
client_side_hash = validator.client_side_hash(self, attr[0])
|
|
25
|
+
# Yeah yeah, #new_record? is not part of ActiveModel :p
|
|
26
|
+
if (can_use_for_client_side_validation?(client_side_hash, validator))
|
|
27
|
+
kind_hash.merge!(validator.kind => client_side_hash.except(:on))
|
|
28
|
+
else
|
|
29
|
+
kind_hash.merge!({})
|
|
30
|
+
end
|
|
31
|
+
end
|
|
21
32
|
|
|
22
|
-
|
|
23
|
-
|
|
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))
|
|
33
|
+
if validator_hash.present?
|
|
34
|
+
attr_hash.merge!(attr[0] => validator_hash)
|
|
27
35
|
else
|
|
28
|
-
|
|
36
|
+
attr_hash
|
|
29
37
|
end
|
|
38
|
+
else
|
|
39
|
+
attr_hash
|
|
30
40
|
end
|
|
31
|
-
|
|
32
|
-
attr_hash.merge!(attr[0] => validator_hash)
|
|
33
|
-
end.delete_if { |key, value| value.blank? }
|
|
41
|
+
end
|
|
34
42
|
end
|
|
35
43
|
|
|
36
44
|
private
|
|
37
45
|
|
|
38
46
|
def can_use_for_client_side_validation?(client_side_hash, validator)
|
|
39
|
-
((self.respond_to?(:new_record?) &&
|
|
47
|
+
((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?) && validator.kind != :block
|
|
40
48
|
end
|
|
41
49
|
end
|
|
42
50
|
end
|
|
@@ -17,7 +17,11 @@ module ClientSideValidations::ActiveRecord
|
|
|
17
17
|
relation = t[attribute].matches(value)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
|
|
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
|
-
|
|
5
|
-
hash
|
|
6
|
-
hash =
|
|
7
|
-
|
|
8
|
-
if
|
|
9
|
-
hash[:scope] = Array.wrap(
|
|
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
|
-
|
|
13
|
-
|
|
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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# This is only used by dependant libraries that need to find the files
|
|
2
|
+
|
|
3
|
+
module ClientSideValidations
|
|
4
|
+
module Files
|
|
5
|
+
Initializer = File.expand_path(File.dirname(__FILE__) + '/../generators/templates/client_side_validations/initializer.rb')
|
|
6
|
+
Javascript = File.expand_path(File.dirname(__FILE__) + '/../../vendor/assets/javascripts/rails.validations.js')
|
|
7
|
+
end
|
|
8
|
+
end
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
module ClientSideValidations
|
|
2
2
|
module Formtastic
|
|
3
|
-
module
|
|
3
|
+
module FormBuilder
|
|
4
4
|
|
|
5
5
|
def self.included(base)
|
|
6
6
|
base.class_eval do
|
|
7
7
|
def self.client_side_form_settings(options, form_helper)
|
|
8
8
|
{
|
|
9
9
|
:type => self.to_s,
|
|
10
|
-
:inline_error_class => ::Formtastic::
|
|
10
|
+
:inline_error_class => ::Formtastic::FormBuilder.default_inline_error_class
|
|
11
11
|
}
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -17,5 +17,5 @@ module ClientSideValidations
|
|
|
17
17
|
end
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
Formtastic::
|
|
20
|
+
Formtastic::FormBuilder.send(:include, ClientSideValidations::Formtastic::FormBuilder)
|
|
21
21
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
|
|
3
|
+
require 'client_side_validations/core_ext'
|
|
4
|
+
|
|
3
5
|
module ClientSideValidations
|
|
4
6
|
|
|
5
7
|
module Middleware
|
|
6
|
-
|
|
7
8
|
class Validators
|
|
8
9
|
def initialize(app)
|
|
9
10
|
@app = app
|
|
@@ -11,7 +12,7 @@ module ClientSideValidations
|
|
|
11
12
|
|
|
12
13
|
def call(env)
|
|
13
14
|
case env['PATH_INFO']
|
|
14
|
-
when %r{\/validators\/(\w+)
|
|
15
|
+
when %r{\/validators\/(\w+)}
|
|
15
16
|
"::ClientSideValidations::Middleware::#{$1.camelize}".constantize.new(env).response
|
|
16
17
|
else
|
|
17
18
|
@app.call(env)
|
|
@@ -63,6 +64,8 @@ module ClientSideValidations
|
|
|
63
64
|
middleware_klass = ClientSideValidations::ActiveRecord::Middleware
|
|
64
65
|
elsif (defined?(::Mongoid::Document) && klass.included_modules.include?(::Mongoid::Document))
|
|
65
66
|
middleware_klass = ClientSideValidations::Mongoid::Middleware
|
|
67
|
+
elsif (defined?(::MongoMapper::Document) && klass.included_modules.include?(::MongoMapper::Document))
|
|
68
|
+
middleware_klass = ClientSideValidations::MongoMapper::Middleware
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
middleware_klass.is_unique?(klass, attribute, value, request.params)
|
|
@@ -72,11 +75,6 @@ module ClientSideValidations
|
|
|
72
75
|
parent_key = (request.params.keys - IGNORE_PARAMS).first
|
|
73
76
|
end
|
|
74
77
|
end
|
|
75
|
-
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
class Engine < ::Rails::Engine
|
|
79
|
-
config.app_middleware.use ClientSideValidations::Middleware::Validators
|
|
80
78
|
end
|
|
81
79
|
|
|
82
80
|
end
|
|
@@ -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
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module ClientSideValidations::MongoMapper
|
|
2
|
+
module Uniqueness
|
|
3
|
+
def client_side_hash(model, attribute)
|
|
4
|
+
hash = {}
|
|
5
|
+
hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
|
|
6
|
+
hash[:case_sensitive] = options[:case_sensitive] if options.key?(: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
|
+
scope_hash.merge!(scope_item => model.send(scope_item))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
unless model.class.name.demodulize == model.class.name
|
|
15
|
+
hash[:class] = model.class.name.underscore
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
hash
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def message_type
|
|
24
|
+
:taken
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
@@ -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
|
+
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
module ClientSideValidations::Mongoid
|
|
2
2
|
module Uniqueness
|
|
3
3
|
def client_side_hash(model, attribute)
|
|
4
|
-
|
|
5
|
-
hash
|
|
6
|
-
hash =
|
|
7
|
-
|
|
8
|
-
if
|
|
9
|
-
hash[:scope] = Array.wrap(
|
|
4
|
+
hash = {}
|
|
5
|
+
hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
|
|
6
|
+
hash[:case_sensitive] = options[:case_sensitive] if options.key?(: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
|
-
|
|
13
|
-
|
|
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
|
|
@@ -1,8 +1,13 @@
|
|
|
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
|
-
require 'client_side_validations/mongoid'
|
|
6
|
-
require 'client_side_validations/
|
|
7
|
-
require 'client_side_validations/
|
|
6
|
+
require 'client_side_validations/mongoid' if defined?(::Mongoid)
|
|
7
|
+
require 'client_side_validations/mongo_mapper' if defined?(::MongoMapper)
|
|
8
|
+
require 'client_side_validations/action_view' if defined?(::ActionView)
|
|
9
|
+
if defined?(::Rails)
|
|
10
|
+
require 'client_side_validations/middleware'
|
|
11
|
+
require 'client_side_validations/engine'
|
|
12
|
+
end
|
|
8
13
|
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module ClientSideValidations
|
|
2
|
+
module Generators
|
|
3
|
+
class CopyAssetGenerator < Rails::Generators::Base
|
|
4
|
+
source_root File.expand_path('../../../../vendor/assets/javascripts', __FILE__)
|
|
5
|
+
if Rails.version >= '3.1'
|
|
6
|
+
desc 'Creates a ClientSideValidations initializer and copies rails.validations.js to app/assets/javascripts.'
|
|
7
|
+
else
|
|
8
|
+
desc 'Creates a ClientSideValidations initializer and copies rails.validations.js to public/javascripts.'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def copy_javascript_asset
|
|
12
|
+
if Rails.version >= '3.1'
|
|
13
|
+
destination = 'app/assets/javascripts'
|
|
14
|
+
else
|
|
15
|
+
destination = 'public/javascripts'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
copy_file 'rails.validations.js', "#{destination}/rails.validations.js"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|