client_side_validations 3.2.0.beta.6 → 3.2.0.rc.1
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/lib/client_side_validations/action_view/form_builder.rb +15 -105
- data/lib/client_side_validations/action_view/form_helper.rb +24 -8
- data/lib/client_side_validations/active_model.rb +94 -11
- data/lib/client_side_validations/active_model/exclusion.rb +14 -2
- data/lib/client_side_validations/active_model/format.rb +21 -0
- data/lib/client_side_validations/active_model/inclusion.rb +13 -2
- data/lib/client_side_validations/active_model/length.rb +1 -1
- data/lib/client_side_validations/active_model/numericality.rb +8 -1
- data/lib/client_side_validations/active_record/middleware.rb +1 -1
- data/lib/client_side_validations/active_record/uniqueness.rb +1 -1
- data/lib/client_side_validations/core_ext/regexp.rb +1 -2
- data/lib/client_side_validations/version.rb +1 -1
- data/lib/generators/client_side_validations/copy_assets_generator.rb +3 -1
- data/vendor/assets/javascripts/rails.validations.js +342 -331
- metadata +3 -3
@@ -5,7 +5,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
5
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
|
+
build_validation_options(method, options)
|
9
9
|
options.delete(:validate)
|
10
10
|
#{selector}_without_client_side_validations(method, options)
|
11
11
|
end
|
@@ -36,7 +36,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
36
36
|
|
37
37
|
def initialize_with_client_side_validations(object_name, object, template, options, proc)
|
38
38
|
initialize_without_client_side_validations(object_name, object, template, options, proc)
|
39
|
-
@options[:validators] = {}
|
39
|
+
@options[:validators] = { object => {} }
|
40
40
|
end
|
41
41
|
|
42
42
|
def fields_for_with_client_side_validations(record_or_name_or_array, *args, &block)
|
@@ -46,137 +46,47 @@ module ClientSideValidations::ActionView::Helpers
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def check_box_with_client_side_validations(method, options = {}, checked_value = "1", unchecked_value = "0")
|
49
|
-
|
49
|
+
build_validation_options(method, options)
|
50
|
+
options.delete(:validate)
|
50
51
|
check_box_without_client_side_validations(method, options, checked_value, unchecked_value)
|
51
52
|
end
|
52
53
|
|
53
54
|
def radio_button_with_client_side_validations(method, tag_value, options = {})
|
54
|
-
|
55
|
+
build_validation_options(method, options)
|
56
|
+
options.delete(:validate)
|
55
57
|
radio_button_without_client_side_validations(method, tag_value, options)
|
56
58
|
end
|
57
59
|
|
58
60
|
def select_with_client_side_validations(method, choices, options = {}, html_options = {})
|
59
|
-
|
61
|
+
build_validation_options(method, html_options.merge(:validate => options[:validate]))
|
60
62
|
select_without_client_side_validations(method, choices, options, html_options)
|
61
63
|
end
|
62
64
|
|
63
65
|
def collection_select_with_client_side_validations(method, collection, value_method, text_method, options = {}, html_options = {})
|
64
|
-
|
66
|
+
build_validation_options(method, html_options.merge(:validate => options[:validate]))
|
65
67
|
collection_select_without_client_side_validations(method, collection, value_method, text_method, options, html_options)
|
66
68
|
end
|
67
69
|
|
68
70
|
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
|
-
|
71
|
+
build_validation_options(method, html_options.merge(:validate => options[:validate]))
|
70
72
|
grouped_collection_select_without_client_side_validations(method, collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
|
71
73
|
end
|
72
74
|
|
73
75
|
def time_zone_select_with_client_side_validations(method, priority_zones = nil, options = {}, html_options = {})
|
74
|
-
|
76
|
+
build_validation_options(method, html_options.merge(:validate => options[:validate]))
|
75
77
|
time_zone_select_without_client_side_validations(method, priority_zones = nil, options, html_options)
|
76
78
|
end
|
77
79
|
|
78
80
|
private
|
79
81
|
|
80
|
-
def
|
81
|
-
if @options[:validate]
|
82
|
-
options.merge!("data-validate" => true)
|
82
|
+
def build_validation_options(method, options = {})
|
83
|
+
if @options[:validate]
|
83
84
|
name = options[:name] || "#{@object_name}[#{method}]"
|
84
85
|
child_index = @options[:child_index] ? "(\\d+|#{Regexp.escape(@options[:child_index])})" : "\\d+"
|
85
|
-
name = name.gsub(/_attributes\]\[#{child_index}\]/, '_attributes][]')
|
86
|
-
|
86
|
+
name = name.to_s.gsub(/_attributes\]\[#{child_index}\]/, '_attributes][]')
|
87
|
+
name = "#{name}#{options[:multiple] ? "[]" : nil}"
|
88
|
+
@options[:validators][@object][method] = { :name => name, :options => options[:validate] }
|
87
89
|
end
|
88
90
|
end
|
89
|
-
|
90
|
-
def filter_validators(method, filters)
|
91
|
-
if validators = @object.client_side_validation_hash[method]
|
92
|
-
unfiltered_validators = validators.inject({}) do |unfiltered_validators, validator|
|
93
|
-
kind = validator.first
|
94
|
-
unfiltered_validators[kind] = validator.last.inject([]) do |validators_array, validator_hash|
|
95
|
-
if has_filter_for_validator?(kind, filters)
|
96
|
-
if filter_validator?(kind, filters)
|
97
|
-
next
|
98
|
-
elsif force_validator_despite_conditional?(kind, filters) && !can_run_validator?(validator_hash, method)
|
99
|
-
next
|
100
|
-
end
|
101
|
-
else
|
102
|
-
if (conditional = (validator_hash[:if] || validator_hash[:unless]))
|
103
|
-
result = case conditional
|
104
|
-
when Symbol
|
105
|
-
if @object.respond_to?(conditional)
|
106
|
-
@object.send(conditional)
|
107
|
-
else
|
108
|
-
raise(ArgumentError, "unknown method called '#{conditional}'")
|
109
|
-
end
|
110
|
-
when String
|
111
|
-
eval(conditional)
|
112
|
-
when Proc
|
113
|
-
conditional.call(@object)
|
114
|
-
end
|
115
|
-
|
116
|
-
# :if was specified and result is false OR :unless was specified and result was true
|
117
|
-
if (validator_hash[:if] && !result) || (validator_hash[:unless] && result)
|
118
|
-
next
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
end
|
123
|
-
|
124
|
-
validators_array << validator_hash.clone
|
125
|
-
validators_array.last.delete_if { |key, value| key == :if || key == :unless }
|
126
|
-
validators_array
|
127
|
-
end
|
128
|
-
|
129
|
-
unfiltered_validators
|
130
|
-
end
|
131
|
-
|
132
|
-
unfiltered_validators.delete_if { |k, v| v.nil? }
|
133
|
-
unfiltered_validators.empty? ? nil : unfiltered_validators
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
def has_filter_for_validator?(kind, filters)
|
138
|
-
filters && (filters == true || filters.key?(kind))
|
139
|
-
end
|
140
|
-
|
141
|
-
def filter_validator?(kind, filters)
|
142
|
-
filters != true && filters[kind] == false
|
143
|
-
end
|
144
|
-
|
145
|
-
def force_validator_despite_conditional?(kind, filters)
|
146
|
-
filters == true || filters[kind] == true
|
147
|
-
end
|
148
|
-
|
149
|
-
def can_run_validator?(validator_hash, method)
|
150
|
-
result = true
|
151
|
-
if_result = run_if_validator(validator_hash[:if], method)
|
152
|
-
unless_result = run_unless_validator(validator_hash[:unless], method)
|
153
|
-
result = result && if_result unless if_result.nil?
|
154
|
-
result = result && unless_result unless unless_result.nil?
|
155
|
-
result
|
156
|
-
end
|
157
|
-
|
158
|
-
def run_if_validator(conditional, method)
|
159
|
-
if conditional
|
160
|
-
if conditional.is_a?(Symbol)
|
161
|
-
conditional_method_is_change_method?(conditional, method) ? true : !!@object.send(conditional)
|
162
|
-
else
|
163
|
-
!!conditional.call(@object)
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def run_unless_validator(conditional, method)
|
169
|
-
if conditional
|
170
|
-
if conditional.is_a?(Symbol)
|
171
|
-
conditional_method_is_change_method?(conditional, method) ? true : !@object.send(conditional)
|
172
|
-
else
|
173
|
-
!conditional.call(@object)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def conditional_method_is_change_method?(conditional, method)
|
179
|
-
conditional.to_sym == "#{method}_changed?".to_sym
|
180
|
-
end
|
181
91
|
end
|
182
92
|
end
|
@@ -2,7 +2,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
2
2
|
module FormHelper
|
3
3
|
class Error < StandardError; end
|
4
4
|
|
5
|
-
def form_for(
|
5
|
+
def form_for(record, *args, &proc)
|
6
6
|
options = args.extract_options!
|
7
7
|
if options[:validate]
|
8
8
|
|
@@ -10,13 +10,11 @@ module ClientSideValidations::ActionView::Helpers
|
|
10
10
|
options[:html] ||= {}
|
11
11
|
options[:html][:novalidate] = 'novalidate'
|
12
12
|
|
13
|
-
case
|
13
|
+
case record
|
14
14
|
when String, Symbol
|
15
|
-
raise ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is
|
16
|
-
when Array
|
17
|
-
object = record_or_name_or_array.last
|
15
|
+
raise ClientSideValidations::ActionView::Helpers::FormHelper::Error, 'Using form_for(:name, @resource) is not supported with ClientSideValidations. Please use form_for(@resource, :as => :name) instead.'
|
18
16
|
else
|
19
|
-
object =
|
17
|
+
object = record.is_a?(Array) ? record.last : record
|
20
18
|
end
|
21
19
|
end
|
22
20
|
|
@@ -24,7 +22,7 @@ module ClientSideValidations::ActionView::Helpers
|
|
24
22
|
|
25
23
|
# Order matters here. Rails mutates the options object
|
26
24
|
html_id = options[:html][:id] if options[:html]
|
27
|
-
form = super(
|
25
|
+
form = super(record, *(args << options), &proc)
|
28
26
|
options[:id] = html_id if html_id
|
29
27
|
script = client_side_form_settings(object, options)
|
30
28
|
|
@@ -64,12 +62,30 @@ module ClientSideValidations::ActionView::Helpers
|
|
64
62
|
# But using String#sub has some issues. Undocumented "features"
|
65
63
|
if script
|
66
64
|
script = script.split(/"validator_hash"/)
|
67
|
-
script = "#{script[0]}#{
|
65
|
+
script = "#{script[0]}#{construct_validators.to_json}#{script[1]}"
|
68
66
|
end
|
69
67
|
|
70
68
|
script
|
71
69
|
end
|
72
70
|
|
71
|
+
def construct_validators
|
72
|
+
@validators.inject({}) do |validator_hash, object_opts|
|
73
|
+
option_hash = object_opts[1].inject({}) do |option_hash, attr|
|
74
|
+
option_hash.merge!(attr[0] => attr[1][:options])
|
75
|
+
end
|
76
|
+
|
77
|
+
validation_hash = object_opts[0].client_side_validation_hash(option_hash)
|
78
|
+
|
79
|
+
option_hash.each_key do |attr|
|
80
|
+
if validation_hash[attr]
|
81
|
+
validator_hash.merge!(object_opts[1][attr][:name] => validation_hash[attr])
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
validator_hash
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
73
89
|
def client_side_form_settings(object, options)
|
74
90
|
if options[:validate]
|
75
91
|
builder = options[:parent_builder]
|
@@ -3,9 +3,8 @@ require 'client_side_validations/core_ext'
|
|
3
3
|
module ClientSideValidations::ActiveModel
|
4
4
|
module Validator
|
5
5
|
|
6
|
-
def client_side_hash(model, attribute)
|
7
|
-
|
8
|
-
{ :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
|
6
|
+
def client_side_hash(model, attribute, force = nil)
|
7
|
+
build_client_side_hash(model, attribute, self.options.dup)
|
9
8
|
end
|
10
9
|
|
11
10
|
def copy_conditional_attributes(to, from)
|
@@ -14,21 +13,25 @@ module ClientSideValidations::ActiveModel
|
|
14
13
|
|
15
14
|
private
|
16
15
|
|
16
|
+
def build_client_side_hash(model, attribute, options)
|
17
|
+
{ :message => model.errors.generate_message(attribute, message_type, options) }.merge(options.except(*::ActiveModel::Errors::CALLBACKS_OPTIONS - [:allow_blank, :if, :unless]))
|
18
|
+
end
|
19
|
+
|
17
20
|
def message_type
|
18
21
|
kind
|
19
22
|
end
|
20
23
|
end
|
21
24
|
|
22
25
|
module Validations
|
23
|
-
def client_side_validation_hash
|
24
|
-
|
26
|
+
def client_side_validation_hash(force = nil)
|
27
|
+
_validators.inject({}) do |attr_hash, attr|
|
25
28
|
unless [nil, :block].include?(attr[0])
|
26
29
|
|
27
30
|
validator_hash = attr[1].inject(Hash.new { |h,k| h[k] = []}) do |kind_hash, validator|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
if can_use_for_client_side_validation?(attr[0], validator, force)
|
32
|
+
if client_side_hash = validator.client_side_hash(self, attr[0], extract_force_option(attr[0], force))
|
33
|
+
kind_hash[validator.kind] << client_side_hash.except(:on, :if, :unless)
|
34
|
+
end
|
32
35
|
end
|
33
36
|
|
34
37
|
kind_hash
|
@@ -47,8 +50,88 @@ module ClientSideValidations::ActiveModel
|
|
47
50
|
|
48
51
|
private
|
49
52
|
|
50
|
-
def
|
51
|
-
|
53
|
+
def extract_force_option(attr, force)
|
54
|
+
case force
|
55
|
+
when FalseClass, TrueClass, NilClass
|
56
|
+
force
|
57
|
+
when Hash
|
58
|
+
extract_force_option(nil, force[attr])
|
59
|
+
else
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def can_use_for_client_side_validation?(attr, validator, force)
|
65
|
+
if validator_turned_off?(attr, validator, force)
|
66
|
+
result = false
|
67
|
+
else
|
68
|
+
# Yeah yeah, #new_record? is not part of ActiveModel :p
|
69
|
+
result = ((self.respond_to?(:new_record?) && validator.options[:on] == (self.new_record? ? :create : :update)) || validator.options[:on].nil?)
|
70
|
+
result = result && validator.kind != :block
|
71
|
+
result = result && uniqueness_validations_allowed_or_not_applicable?(validator)
|
72
|
+
|
73
|
+
if validator.options[:if] || validator.options[:unless]
|
74
|
+
if result = can_force_validator?(attr, validator, force)
|
75
|
+
if validator.options[:if]
|
76
|
+
result = result && run_conditional(validator.options[:if])
|
77
|
+
end
|
78
|
+
if validator.options[:unless]
|
79
|
+
result = result && !run_conditional(validator.options[:unless])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
result
|
86
|
+
end
|
87
|
+
|
88
|
+
def run_conditional(method_name_or_proc)
|
89
|
+
case method_name_or_proc
|
90
|
+
when Proc
|
91
|
+
method_name_or_proc.call(self)
|
92
|
+
else
|
93
|
+
self.send(method_name_or_proc)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def validator_turned_off?(attr, validator, force)
|
98
|
+
case force
|
99
|
+
when FalseClass
|
100
|
+
true
|
101
|
+
when Hash
|
102
|
+
case force[attr]
|
103
|
+
when FalseClass
|
104
|
+
true
|
105
|
+
when Hash
|
106
|
+
force[attr][validator.kind] == false
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
else
|
111
|
+
false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def can_force_validator?(attr, validator, force)
|
116
|
+
case force
|
117
|
+
when TrueClass
|
118
|
+
true
|
119
|
+
when Hash
|
120
|
+
case force[attr]
|
121
|
+
when TrueClass
|
122
|
+
true
|
123
|
+
when Hash
|
124
|
+
force[attr][validator.kind]
|
125
|
+
else
|
126
|
+
false
|
127
|
+
end
|
128
|
+
else
|
129
|
+
if (validator.options[:if] || validator.options[:unless]) =~ /changed\?/
|
130
|
+
true
|
131
|
+
else
|
132
|
+
false
|
133
|
+
end
|
134
|
+
end
|
52
135
|
end
|
53
136
|
|
54
137
|
def uniqueness_validations_allowed_or_not_applicable?(validator)
|
@@ -1,12 +1,24 @@
|
|
1
1
|
module ClientSideValidations::ActiveModel
|
2
2
|
module Exclusion
|
3
3
|
|
4
|
-
def client_side_hash(model, attribute)
|
5
|
-
|
4
|
+
def client_side_hash(model, attribute, force = nil)
|
5
|
+
if options[:in].respond_to?(:call)
|
6
|
+
if force
|
7
|
+
options = self.options.dup
|
8
|
+
options[:in] = options[:in].call(model)
|
9
|
+
hash = build_client_side_hash(model, attribute, options)
|
10
|
+
else
|
11
|
+
return
|
12
|
+
end
|
13
|
+
else
|
14
|
+
hash = build_client_side_hash(model, attribute, self.options.dup)
|
15
|
+
end
|
16
|
+
|
6
17
|
if hash[:in].is_a?(Range)
|
7
18
|
hash[:range] = hash[:in]
|
8
19
|
hash.delete(:in)
|
9
20
|
end
|
21
|
+
|
10
22
|
hash
|
11
23
|
end
|
12
24
|
|
@@ -1,5 +1,26 @@
|
|
1
1
|
module ClientSideValidations::ActiveModel
|
2
2
|
module Format
|
3
|
+
def client_side_hash(model, attribute, force = nil)
|
4
|
+
options = self.options.dup
|
5
|
+
if options[:with].respond_to?(:call)
|
6
|
+
if force
|
7
|
+
options[:with] = options[:with].call(model)
|
8
|
+
build_client_side_hash(model, attribute, options)
|
9
|
+
else
|
10
|
+
return
|
11
|
+
end
|
12
|
+
elsif options[:without].respond_to?(:call)
|
13
|
+
if force
|
14
|
+
options[:without] = options[:without].call(model)
|
15
|
+
build_client_side_hash(model, attribute, options)
|
16
|
+
else
|
17
|
+
return
|
18
|
+
end
|
19
|
+
else
|
20
|
+
super
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
3
24
|
private
|
4
25
|
|
5
26
|
def message_type
|
@@ -1,8 +1,19 @@
|
|
1
1
|
module ClientSideValidations::ActiveModel
|
2
2
|
module Inclusion
|
3
3
|
|
4
|
-
def client_side_hash(model, attribute)
|
5
|
-
|
4
|
+
def client_side_hash(model, attribute, force = nil)
|
5
|
+
if options[:in].respond_to?(:call)
|
6
|
+
if force
|
7
|
+
options = self.options.dup
|
8
|
+
options[:in] = options[:in].call(model)
|
9
|
+
hash = build_client_side_hash(model, attribute, options)
|
10
|
+
else
|
11
|
+
return
|
12
|
+
end
|
13
|
+
else
|
14
|
+
hash = build_client_side_hash(model, attribute, self.options.dup)
|
15
|
+
end
|
16
|
+
|
6
17
|
if hash[:in].is_a?(Range)
|
7
18
|
hash[:range] = hash[:in]
|
8
19
|
hash.delete(:in)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ClientSideValidations::ActiveModel
|
2
2
|
module Length
|
3
3
|
|
4
|
-
def client_side_hash(model, attribute)
|
4
|
+
def client_side_hash(model, attribute, force = nil)
|
5
5
|
options = self.options.dup
|
6
6
|
hash = { :messages => {} }
|
7
7
|
hash[:js_tokenizer] = options[:js_tokenizer] if options[:js_tokenizer]
|