adamhunter-client_side_validations 2.9.10
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/LICENSE +24 -0
- data/README.markdown +132 -0
- data/generators/client_side_validations/client_side_validations_generator.rb +17 -0
- data/javascript/lib/client_side_validations.js +93 -0
- data/javascript/lib/jquery-validation.js +1146 -0
- data/lib/client_side_validations.rb +60 -0
- data/lib/client_side_validations/adapters/action_view.rb +153 -0
- data/lib/client_side_validations/adapters/active_model.rb +137 -0
- data/lib/client_side_validations/adapters/orm_base.rb +89 -0
- data/lib/client_side_validations/orm.rb +226 -0
- data/lib/client_side_validations/rails.rb +11 -0
- data/lib/client_side_validations/template.rb +3 -0
- data/lib/generators/client_side_validations_generator.rb +15 -0
- metadata +533 -0
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'json'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module ClientSideValidations
|
6
|
+
def self.default_options=(options)
|
7
|
+
@default_options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.default_options
|
11
|
+
@default_options
|
12
|
+
end
|
13
|
+
|
14
|
+
class Uniqueness
|
15
|
+
def initialize(app)
|
16
|
+
@app = app
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(env)
|
20
|
+
# By default CGI::parse will instantize a hash that defaults nil elements to [].
|
21
|
+
# We need to override this
|
22
|
+
case env['PATH_INFO']
|
23
|
+
when %r{^/validations/uniqueness.json}
|
24
|
+
params = {}.merge!(CGI::parse(env['QUERY_STRING']))
|
25
|
+
field = params.keys.first
|
26
|
+
resource, attribute = field.split(/[^\w]/)
|
27
|
+
value = params[field][0]
|
28
|
+
# Because params returns an array for each field value we want to always grab
|
29
|
+
# the first element of the array for id, even if it is nil
|
30
|
+
id = [params["#{resource}[id]"]].flatten.first
|
31
|
+
body = is_unique?(resource, attribute, value, id).to_s
|
32
|
+
[200, {'Content-Type' => 'application/json', 'Content-Length' => "#{body.length}"}, [body]]
|
33
|
+
else
|
34
|
+
@app.call(env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def is_unique?(resource, attribute, value, id = nil)
|
41
|
+
klass = constantize_resource(resource)
|
42
|
+
instance = nil
|
43
|
+
instance = klass.send("find_by_#{attribute}", value)
|
44
|
+
|
45
|
+
if instance
|
46
|
+
return instance.id.to_i == id.to_i
|
47
|
+
else
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def constantize_resource(resource)
|
53
|
+
eval(resource.split('_').map{ |word| word.capitalize}.join)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
require 'client_side_validations/orm'
|
59
|
+
require 'client_side_validations/template'
|
60
|
+
require 'client_side_validations/rails' if defined?(Rails)
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module ClientSideValidations
|
2
|
+
module Adapters
|
3
|
+
module ActionView
|
4
|
+
module BaseMethods
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
form_method = base.instance_method(:form_for)
|
8
|
+
base.class_eval do
|
9
|
+
attr_accessor :validate_options
|
10
|
+
|
11
|
+
define_method(:form_for) do |record_or_name_or_array, *args, &proc|
|
12
|
+
options = args.extract_options!.symbolize_keys!
|
13
|
+
script = ""
|
14
|
+
if validations = options.delete(:validations)
|
15
|
+
set_validate_options(validations, record_or_name_or_array, options)
|
16
|
+
unless options.has_key?(:html)
|
17
|
+
options[:html] = {}
|
18
|
+
end
|
19
|
+
options[:html]['data-csv'] = validate_options.delete('data-csv')
|
20
|
+
script = %{<script type='text/javascript'>var #{options[:html]['data-csv']}_validate_options=#{validate_options.to_json};</script>}
|
21
|
+
end
|
22
|
+
args << options
|
23
|
+
result = form_method.bind(self).call(record_or_name_or_array, *args, &proc)
|
24
|
+
if rails3?
|
25
|
+
result += script.html_safe
|
26
|
+
else
|
27
|
+
concat(script)
|
28
|
+
end
|
29
|
+
result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def rails3?
|
37
|
+
version =
|
38
|
+
if defined?(ActionPack::VERSION::MAJOR)
|
39
|
+
ActionPack::VERSION::MAJOR
|
40
|
+
end
|
41
|
+
!version.blank? && version >= 3
|
42
|
+
end
|
43
|
+
|
44
|
+
def set_validate_options(validations, record_or_name_or_array, form_for_options)
|
45
|
+
options = ::ClientSideValidations.default_options || { }
|
46
|
+
|
47
|
+
case validations
|
48
|
+
when true
|
49
|
+
object_name = get_object_name(record_or_name_or_array, form_for_options)
|
50
|
+
data_csv = get_data_csv(record_or_name_or_array, form_for_options)
|
51
|
+
validate_options = rules_and_messages(record_or_name_or_array)
|
52
|
+
when Hash
|
53
|
+
validations.symbolize_keys!
|
54
|
+
if validations.has_key?(:instance)
|
55
|
+
object_name = get_object_name(validations[:instance], form_for_options)
|
56
|
+
data_csv = get_data_csv(validations[:instance], form_for_options)
|
57
|
+
validate_options = validations[:instance].validate_options
|
58
|
+
elsif validations.has_key?(:class)
|
59
|
+
object_name = get_object_name(validations[:class], form_for_options)
|
60
|
+
data_csv = get_data_csv(validations[:class], form_for_options)
|
61
|
+
validate_options = validations[:class].new.validate_options
|
62
|
+
else
|
63
|
+
object_name = get_object_name(record_or_name_or_array, form_for_options)
|
64
|
+
data_csv = get_data_csv(record_or_name_or_array, form_for_options)
|
65
|
+
validate_options = rules_and_messages(record_or_name_or_array)
|
66
|
+
end
|
67
|
+
|
68
|
+
options.merge!(validations[:options] || {})
|
69
|
+
else
|
70
|
+
object_name = get_object_name(validations, form_for_options)
|
71
|
+
data_csv = get_data_csv(validations, form_for_options)
|
72
|
+
validate_options = validations.new.validate_options
|
73
|
+
end
|
74
|
+
|
75
|
+
self.validate_options = build_validate_options(object_name, validate_options, options, data_csv)
|
76
|
+
end
|
77
|
+
|
78
|
+
def build_validate_options(object_name, validate_options, options, data_csv)
|
79
|
+
%w{rules messages}.each do |option|
|
80
|
+
validate_options[option].keys.each do |key|
|
81
|
+
validate_options[option]["#{object_name}[#{key}]"] = validate_options[option].delete(key)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
validate_options['options'] = options unless options.empty?
|
86
|
+
validate_options['data-csv'] = data_csv
|
87
|
+
validate_options
|
88
|
+
end
|
89
|
+
|
90
|
+
def rules_and_messages(record_or_name_or_array)
|
91
|
+
case record_or_name_or_array
|
92
|
+
when String, Symbol
|
93
|
+
record_or_name_or_array.to_s.camelize.constantize.new.validate_options
|
94
|
+
when Array
|
95
|
+
rules_and_messages(record_or_name_or_array.last)
|
96
|
+
else
|
97
|
+
record_or_name_or_array.validate_options
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def get_data_csv(object, form_for_options)
|
102
|
+
case object
|
103
|
+
when String, Symbol
|
104
|
+
form_for_options[:as] || object.to_s
|
105
|
+
when Array
|
106
|
+
get_data_csv(object.last, form_for_options)
|
107
|
+
when Class
|
108
|
+
form_for_options[:as] || object.to_s.underscore
|
109
|
+
else
|
110
|
+
if object.respond_to?(:persisted?) && object.persisted?
|
111
|
+
form_for_options[:as] ? "#{form_for_options[:as]}_edit" : dom_id(object)
|
112
|
+
else
|
113
|
+
form_for_options[:as] ? "#{form_for_options[:as]}_new" : dom_id(object)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def get_object_name(object, form_for_options)
|
119
|
+
case object
|
120
|
+
when String, Symbol
|
121
|
+
form_for_options[:as] || object.to_s
|
122
|
+
when Array
|
123
|
+
get_object_name(object.last, form_for_options)
|
124
|
+
when Class
|
125
|
+
get_object_name(object.new, form_for_options)
|
126
|
+
else
|
127
|
+
if rails3?
|
128
|
+
form_for_options[:as] || ::ActiveModel::Naming.singular(object)
|
129
|
+
else
|
130
|
+
form_for_options[:as] || ::ActionController::RecordIdentifier.singular_class_name(object)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end # BaseMethods
|
135
|
+
|
136
|
+
module FormBuilderMethods
|
137
|
+
|
138
|
+
def client_side_validations(options = {})
|
139
|
+
@template.send(:client_side_validations, @object_name, objectify_options(options))
|
140
|
+
end
|
141
|
+
|
142
|
+
end # FormBuilderMethods
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
ActionView::Base.class_eval do
|
148
|
+
include ClientSideValidations::Adapters::ActionView::BaseMethods
|
149
|
+
end
|
150
|
+
|
151
|
+
ActionView::Helpers::FormBuilder.class_eval do
|
152
|
+
include ClientSideValidations::Adapters::ActionView::FormBuilderMethods
|
153
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'client_side_validations/adapters/orm_base'
|
2
|
+
|
3
|
+
module ClientSideValidations
|
4
|
+
module Adapters
|
5
|
+
class ActiveModel < ORMBase
|
6
|
+
|
7
|
+
def validations_to_hash(attr)
|
8
|
+
base._validators[attr.to_sym].inject({}) do |hash, validation|
|
9
|
+
validation.instance_variable_set('@options', validation.options.dup)
|
10
|
+
hash.merge!(build_validation_hash(validation.dup))
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def build_validation_hash(validation, message_key = 'message')
|
17
|
+
if validation.kind == :inclusion || validation.kind == :exclusion
|
18
|
+
validation.options[:in] = validation.options[:in].to_a
|
19
|
+
end
|
20
|
+
|
21
|
+
if validation.kind == :size
|
22
|
+
validation.kind = :length
|
23
|
+
end
|
24
|
+
|
25
|
+
if validation.kind == :length &&
|
26
|
+
(range = (validation.options.delete(:within) || validation.options.delete(:in)))
|
27
|
+
validation.options[:minimum] = range.first
|
28
|
+
validation.options[:maximum] = range.last
|
29
|
+
elsif validation.kind == :inclusion || validation.kind == :exclusion
|
30
|
+
validation.options[:in] = validation.options[:in].to_a
|
31
|
+
end
|
32
|
+
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def supported_validation?(validation)
|
37
|
+
SupportedValidations.include?(validation.kind.to_sym)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_validation_message(validation)
|
41
|
+
default = case validation.kind
|
42
|
+
when :presence
|
43
|
+
I18n.translate(i18n_prefix + 'errors.messages.blank')
|
44
|
+
when :format
|
45
|
+
I18n.translate(i18n_prefix + 'errors.messages.invalid')
|
46
|
+
when :length
|
47
|
+
if count = validation.options[:is]
|
48
|
+
I18n.translate(i18n_prefix + 'errors.messages.wrong_length').sub(orm_error_interpolation(:count), count.to_s)
|
49
|
+
elsif count = validation.options[:minimum]
|
50
|
+
I18n.translate(i18n_prefix + 'errors.messages.too_short').sub(orm_error_interpolation(:count), count.to_s)
|
51
|
+
elsif count = validation.options[:maximum]
|
52
|
+
I18n.translate(i18n_prefix + 'errors.messages.too_long').sub(orm_error_interpolation(:count), count.to_s)
|
53
|
+
end
|
54
|
+
when :numericality
|
55
|
+
if validation.options[:only_integer]
|
56
|
+
I18n.translate(i18n_prefix + 'errors.messages.not_a_number')
|
57
|
+
elsif count = validation.options[:greater_than]
|
58
|
+
I18n.translate(i18n_prefix + 'errors.messages.greater_than').sub(orm_error_interpolation(:count), count.to_s)
|
59
|
+
elsif count = validation.options[:greater_than_or_equal_to]
|
60
|
+
I18n.translate(i18n_prefix + 'errors.messages.greater_than_or_equal_to').sub(orm_error_interpolation(:count), count.to_s)
|
61
|
+
elsif count = validation.options[:less_than]
|
62
|
+
I18n.translate(i18n_prefix + 'errors.messages.less_than').sub(orm_error_interpolation(:count), count.to_s)
|
63
|
+
elsif count = validation.options[:less_than_or_equal_to]
|
64
|
+
I18n.translate(i18n_prefix + 'errors.messages.less_than_or_equal_to').sub(orm_error_interpolation(:count), count.to_s)
|
65
|
+
elsif validation.options[:odd]
|
66
|
+
I18n.translate(i18n_prefix + 'errors.messages.odd')
|
67
|
+
elsif validation.options[:even]
|
68
|
+
I18n.translate(i18n_prefix + 'errors.messages.even')
|
69
|
+
else
|
70
|
+
I18n.translate(i18n_prefix + 'errors.messages.not_a_number')
|
71
|
+
end
|
72
|
+
when :uniqueness
|
73
|
+
if defined?(ActiveRecord) && base.kind_of?(ActiveRecord::Base)
|
74
|
+
I18n.translate('activerecord.errors.messages.taken')
|
75
|
+
elsif defined?(Mongoid) && base.class.included_modules.include?(Mongoid::Document)
|
76
|
+
if ruby18?
|
77
|
+
I18n.translate('errors.messages.taken')
|
78
|
+
else
|
79
|
+
I18n.translate('activemodel.errors.messages.taken')
|
80
|
+
end
|
81
|
+
end
|
82
|
+
when :confirmation
|
83
|
+
I18n.translate(i18n_prefix + 'errors.messages.confirmation')
|
84
|
+
when :acceptance
|
85
|
+
I18n.translate(i18n_prefix + 'errors.messages.accepted')
|
86
|
+
when :inclusion
|
87
|
+
I18n.translate(i18n_prefix + 'errors.messages.inclusion')
|
88
|
+
when :exclusion
|
89
|
+
I18n.translate(i18n_prefix + 'errors.messages.exclusion')
|
90
|
+
end
|
91
|
+
|
92
|
+
message = validation.options.delete(:message)
|
93
|
+
if message.kind_of?(String)
|
94
|
+
message
|
95
|
+
elsif message.kind_of?(Symbol)
|
96
|
+
I18n.translate(i18n_prefix + "errors.models.#{base.class.to_s.downcase}.attributes.#{validation.attributes.first}.#{message}")
|
97
|
+
else
|
98
|
+
default
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_validation_method(validation)
|
103
|
+
validation.kind.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
def ruby18?
|
107
|
+
ruby_split[0] == '1' && ruby_split[1] == '8'
|
108
|
+
end
|
109
|
+
|
110
|
+
def ruby19?
|
111
|
+
ruby_split[0] == '1' && ruby_split[1] == '9'
|
112
|
+
end
|
113
|
+
|
114
|
+
def ruby_split
|
115
|
+
RUBY_VERSION.split('.')
|
116
|
+
end
|
117
|
+
|
118
|
+
def i18n_prefix
|
119
|
+
if defined?(::ActiveModel)
|
120
|
+
''
|
121
|
+
else # ActiveRecord 2.x
|
122
|
+
'activerecord.'
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def orm_error_interpolation(name)
|
127
|
+
if defined?(::ActiveModel)
|
128
|
+
"%{#{name}}"
|
129
|
+
|
130
|
+
else # ActiveRecord 2.x
|
131
|
+
"{{#{name}}}"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module ClientSideValidations
|
2
|
+
module Adapters
|
3
|
+
class ORMBase
|
4
|
+
attr_accessor :base
|
5
|
+
|
6
|
+
def initialize(base)
|
7
|
+
self.base = base
|
8
|
+
end
|
9
|
+
|
10
|
+
def validations_to_hash(attr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def validation_fields
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
SupportedValidations = [:presence, :format, :length, :numericality, :uniqueness,
|
20
|
+
:confirmation, :acceptance, :inclusion, :exclusion]
|
21
|
+
|
22
|
+
def build_validation_hash(validation, message_key = 'message')
|
23
|
+
if can_validate?(validation)
|
24
|
+
validation_hash = {}
|
25
|
+
message = get_validation_message(validation)
|
26
|
+
options = get_validation_options(validation)
|
27
|
+
method = get_validation_method(validation)
|
28
|
+
|
29
|
+
if validation.options.has_key?(:minimum) && validation.options.has_key?(:maximum)
|
30
|
+
message_key = 'message_min'
|
31
|
+
cloned_validation = validation.clone
|
32
|
+
cloned_validation.options.delete(:minimum)
|
33
|
+
validation_hash.merge!(build_validation_hash(cloned_validation, 'message_max'))
|
34
|
+
end
|
35
|
+
|
36
|
+
new_validation_hash = { method => { message_key => message }.merge(options.stringify_keys) }
|
37
|
+
|
38
|
+
unless validation_hash.empty?
|
39
|
+
validation_hash["length"].merge!(new_validation_hash["length"])
|
40
|
+
validation_hash
|
41
|
+
else
|
42
|
+
new_validation_hash
|
43
|
+
end
|
44
|
+
else
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def can_validate?(validation)
|
50
|
+
if supported_validation?(validation)
|
51
|
+
if on = validation.options[:on]
|
52
|
+
on = on.to_sym
|
53
|
+
(on == :save) ||
|
54
|
+
(on == :create && base.new_record?) ||
|
55
|
+
(on == :update && !base.new_record?)
|
56
|
+
elsif(if_condition = (validation.options[:if] || validation.options[:allow_validation]))
|
57
|
+
base.instance_eval(if_condition.to_s)
|
58
|
+
elsif(unless_condition = (validation.options[:unless] || validation.options[:skip_validation]))
|
59
|
+
!base.instance_eval(unless_condition.to_s)
|
60
|
+
else
|
61
|
+
true
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_validation_message(validation)
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_validation_options(validation)
|
70
|
+
options = validation.options.clone
|
71
|
+
options.symbolize_keys!
|
72
|
+
deleteable_keys = [:on, :tokenizer, :allow_nil, :case_sensitive, :accept, :if, :unless, :allow_validation]
|
73
|
+
options.delete(:maximum) if options.has_key?(:minimum)
|
74
|
+
options.delete_if { |k, v| deleteable_keys.include?(k) }
|
75
|
+
if options[:with].kind_of?(Regexp)
|
76
|
+
options[:with] = options[:with].inspect.to_s.gsub("\\A","^").gsub("\\Z","$").sub(%r{^/},"").sub(%r{/i?$}, "")
|
77
|
+
end
|
78
|
+
if options[:only_integer] == false
|
79
|
+
options.delete(:only_integer)
|
80
|
+
end
|
81
|
+
options
|
82
|
+
end
|
83
|
+
|
84
|
+
def get_validation_method(validation)
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
require 'client_side_validations/adapters/active_model'
|
2
|
+
|
3
|
+
module ClientSideValidations
|
4
|
+
module ORM
|
5
|
+
def validate_options
|
6
|
+
ValidateOptions.new(self).to_hash
|
7
|
+
end
|
8
|
+
|
9
|
+
def validation_fields
|
10
|
+
self._validators.keys
|
11
|
+
end
|
12
|
+
|
13
|
+
class ValidateOptions
|
14
|
+
attr_accessor :base
|
15
|
+
|
16
|
+
def initialize(base)
|
17
|
+
self.base = base
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_hash
|
21
|
+
rules = Hash.new { |h, field| h[field] = {} }
|
22
|
+
messages = Hash.new { |h, field| h[field] = {} }
|
23
|
+
base.validation_fields.each do |field|
|
24
|
+
validations = validations_for(field)
|
25
|
+
rules[field.to_s].merge!(extract_rules(validations, field))
|
26
|
+
messages[field.to_s].merge!(extract_messages(validations))
|
27
|
+
end
|
28
|
+
{"rules" => rules, "messages" => messages}
|
29
|
+
end
|
30
|
+
|
31
|
+
def validations_for(field)
|
32
|
+
adapter.validations_to_hash(field)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def convert_kind(kind, options = nil)
|
38
|
+
case kind
|
39
|
+
when 'acceptance', 'exclusion', 'inclusion', 'format', 'confirmation'
|
40
|
+
kind
|
41
|
+
when 'presence'
|
42
|
+
'required'
|
43
|
+
when 'numericality'
|
44
|
+
if options['only_integer']
|
45
|
+
'digits'
|
46
|
+
elsif options['greater_than']
|
47
|
+
'greater_than'
|
48
|
+
elsif options['greater_than_or_equal_to']
|
49
|
+
'min'
|
50
|
+
elsif options['less_than']
|
51
|
+
'less_than'
|
52
|
+
elsif options['less_than_or_equal_to']
|
53
|
+
'max'
|
54
|
+
elsif options['odd']
|
55
|
+
'odd'
|
56
|
+
elsif options['even']
|
57
|
+
'even'
|
58
|
+
else
|
59
|
+
'numericality'
|
60
|
+
end
|
61
|
+
when 'length'
|
62
|
+
if options['is']
|
63
|
+
'islength'
|
64
|
+
elsif options['minimum'] && options['maximum']
|
65
|
+
['minlength', 'maxlength']
|
66
|
+
elsif options['minimum']
|
67
|
+
'minlength'
|
68
|
+
elsif options['maximum']
|
69
|
+
'maxlength'
|
70
|
+
end
|
71
|
+
when 'uniqueness'
|
72
|
+
'remote'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def extract_rules(validations, field = nil)
|
77
|
+
rules = {}
|
78
|
+
validations.each do |kind, options|
|
79
|
+
kind = convert_kind(kind, options)
|
80
|
+
value = case kind
|
81
|
+
when 'acceptance', 'required', 'digits', 'numericality', 'odd', 'even', 'confirmation'
|
82
|
+
true
|
83
|
+
when 'greater_than', 'less_than'
|
84
|
+
options[kind]
|
85
|
+
when 'max'
|
86
|
+
options['less_than_or_equal_to']
|
87
|
+
when 'min'
|
88
|
+
options['greater_than_or_equal_to']
|
89
|
+
when 'format'
|
90
|
+
options['with']
|
91
|
+
when 'exclusion', 'inclusion'
|
92
|
+
options['in']
|
93
|
+
when 'islength'
|
94
|
+
options['is']
|
95
|
+
when 'minlength'
|
96
|
+
options['minimum']
|
97
|
+
when 'maxlength'
|
98
|
+
options['maximum']
|
99
|
+
when 'remote'
|
100
|
+
if base.new_record?
|
101
|
+
data = {}
|
102
|
+
else
|
103
|
+
data = { "#{base.class.to_s.underscore}[id]" => base.id}
|
104
|
+
end
|
105
|
+
{'url' => '/validations/uniqueness.json', 'data' => data}
|
106
|
+
end
|
107
|
+
|
108
|
+
unless Array === kind
|
109
|
+
rules[kind] = value
|
110
|
+
else
|
111
|
+
kind.each do |k|
|
112
|
+
special_rule = case k
|
113
|
+
when 'minlength'
|
114
|
+
options['minimum']
|
115
|
+
when 'maxlength'
|
116
|
+
options['maximum']
|
117
|
+
end
|
118
|
+
|
119
|
+
rules[k] = special_rule
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
if numericality?(kind)
|
124
|
+
unless rules['numericality'] || rules['digits']
|
125
|
+
rules['numericality'] = true
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
if required?(kind, options)
|
130
|
+
unless rules['required']
|
131
|
+
rules['required'] = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
rules
|
137
|
+
end
|
138
|
+
|
139
|
+
def extract_messages(validations)
|
140
|
+
messages = {}
|
141
|
+
validations.each do |kind, options|
|
142
|
+
kind = convert_kind(kind, options)
|
143
|
+
unless Array === kind
|
144
|
+
messages[kind] = options['message']
|
145
|
+
else
|
146
|
+
kind.each do |k|
|
147
|
+
special_message = case k
|
148
|
+
when 'minlength'
|
149
|
+
options['message'] = options['message_min']
|
150
|
+
'message_min'
|
151
|
+
when 'maxlength'
|
152
|
+
'message_max'
|
153
|
+
end
|
154
|
+
|
155
|
+
messages[k] = options[special_message]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
if numericality?(kind)
|
160
|
+
messages['numericality'] = I18n.translate(i18n_prefix + 'errors.messages.not_a_number')
|
161
|
+
end
|
162
|
+
|
163
|
+
if required?(kind, options)
|
164
|
+
unless messages['required']
|
165
|
+
if ['greater_than', 'min', 'less_than', 'max', 'odd', 'even'].include?(kind)
|
166
|
+
messages['required'] = I18n.translate(i18n_prefix + 'errors.messages.not_a_number')
|
167
|
+
else
|
168
|
+
messages['required'] = options['message']
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
messages
|
174
|
+
end
|
175
|
+
|
176
|
+
def i18n_prefix
|
177
|
+
if defined?(::ActiveModel)
|
178
|
+
''
|
179
|
+
else # ActiveRecord 2.x
|
180
|
+
'activerecord.'
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def numericality?(kind)
|
185
|
+
['greater_than', 'min', 'less_than', 'max', 'even', 'odd'].include?(kind)
|
186
|
+
end
|
187
|
+
|
188
|
+
def required?(kind, options)
|
189
|
+
case kind
|
190
|
+
when 'digits', 'exclusion', 'inclusion', 'islength', 'minlength', 'remote', 'numericality', 'greater_than', 'min', 'less_than', 'max', 'even', 'odd', 'format'
|
191
|
+
!options['allow_blank']
|
192
|
+
when Array
|
193
|
+
required?('minlength', options) if kind.include?('minlength')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def adapter
|
198
|
+
unless @adapter
|
199
|
+
@adapter = ClientSideValidations::Adapters::ActiveModel.new(base)
|
200
|
+
end
|
201
|
+
@adapter
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
if defined?(::ActiveModel)
|
208
|
+
klass = ::ActiveModel::Validations
|
209
|
+
|
210
|
+
elsif defined?(::ActiveRecord)
|
211
|
+
if ::ActiveRecord::VERSION::MAJOR == 2
|
212
|
+
require 'validation_reflection/active_model'
|
213
|
+
klass = ::ActiveRecord::Base
|
214
|
+
|
215
|
+
ActiveRecord::Base.class_eval do
|
216
|
+
::ActiveRecordExtensions::ValidationReflection.reflected_validations << :validates_size_of
|
217
|
+
::ActiveRecordExtensions::ValidationReflection.install(self)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
if klass
|
223
|
+
klass.class_eval do
|
224
|
+
include ClientSideValidations::ORM
|
225
|
+
end
|
226
|
+
end
|