client_side_validations 3.2.8 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +46 -0
  3. data/README.md +540 -0
  4. data/lib/client_side_validations.rb +0 -1
  5. data/lib/client_side_validations/action_view.rb +4 -3
  6. data/lib/client_side_validations/action_view/form_builder.rb +101 -84
  7. data/lib/client_side_validations/action_view/form_helper.rb +99 -110
  8. data/lib/client_side_validations/action_view/form_tag_helper.rb +13 -9
  9. data/lib/client_side_validations/active_model.rb +95 -80
  10. data/lib/client_side_validations/active_model/absence.rb +11 -0
  11. data/lib/client_side_validations/active_model/acceptance.rb +7 -6
  12. data/lib/client_side_validations/active_model/exclusion.rb +4 -24
  13. data/lib/client_side_validations/active_model/format.rb +24 -23
  14. data/lib/client_side_validations/active_model/inclusion.rb +4 -23
  15. data/lib/client_side_validations/active_model/length.rb +15 -15
  16. data/lib/client_side_validations/active_model/numericality.rb +23 -22
  17. data/lib/client_side_validations/active_model/presence.rb +7 -6
  18. data/lib/client_side_validations/active_record.rb +2 -2
  19. data/lib/client_side_validations/active_record/middleware.rb +41 -39
  20. data/lib/client_side_validations/active_record/uniqueness.rb +24 -23
  21. data/lib/client_side_validations/config.rb +1 -1
  22. data/lib/client_side_validations/core_ext/range.rb +1 -2
  23. data/lib/client_side_validations/core_ext/regexp.rb +6 -4
  24. data/lib/client_side_validations/engine.rb +0 -1
  25. data/lib/client_side_validations/generators.rb +2 -3
  26. data/lib/client_side_validations/generators/rails_validations.rb +2 -3
  27. data/lib/client_side_validations/middleware.rb +17 -24
  28. data/lib/client_side_validations/version.rb +1 -1
  29. data/lib/generators/client_side_validations/copy_assets_generator.rb +7 -11
  30. data/lib/generators/client_side_validations/install_generator.rb +0 -2
  31. data/lib/generators/templates/client_side_validations/initializer.rb +1 -2
  32. data/vendor/assets/javascripts/rails.validations.js +26 -20
  33. metadata +173 -48
  34. data/client_side_validations.gemspec +0 -30
@@ -1,25 +1,27 @@
1
- module ClientSideValidations::ActiveModel
2
- module Numericality
1
+ module ClientSideValidations
2
+ module ActiveModel
3
+ module Numericality
4
+ OPTION_MAP = {}
3
5
 
4
- OPTION_MAP = {}
6
+ def self.included(base)
7
+ OPTION_MAP.merge!(base::CHECKS.keys.inject({}) { |a, e| a.merge!(e => e) })
8
+ end
5
9
 
6
- def self.included(base)
7
- OPTION_MAP.merge!(base::CHECKS.keys.inject({}) { |hash, key| hash.merge!(key => key) })
8
- end
10
+ def client_side_hash(model, attribute, force = nil)
11
+ options = self.options.dup
12
+ hash = { messages: { numericality: model.errors.generate_message(attribute, :not_a_number, options) } }
9
13
 
10
- def client_side_hash(model, attribute, force = nil)
11
- options = self.options.dup
12
- hash = { :messages => { :numericality => model.errors.generate_message(attribute, :not_a_number, options) } }
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
13
18
 
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
19
+ hash[:allow_blank] = true if options[:allow_nil] || options[:allow_blank]
18
20
 
19
- hash[:allow_blank] = true if options[:allow_nil] || options[:allow_blank]
21
+ OPTION_MAP.each do |option, message_type|
22
+ count = options[option]
23
+ next unless count
20
24
 
21
- OPTION_MAP.each do |option, message_type|
22
- if count = options[option]
23
25
  if count.respond_to?(:call)
24
26
  if force
25
27
  count = count.call(model)
@@ -27,16 +29,15 @@ module ClientSideValidations::ActiveModel
27
29
  next
28
30
  end
29
31
  end
30
- hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(:count => count))
32
+
33
+ hash[:messages][option] = model.errors.generate_message(attribute, message_type, options.merge(count: count))
31
34
  hash[option] = count
32
35
  end
33
- end
34
36
 
35
- copy_conditional_attributes(hash, options)
37
+ copy_conditional_attributes(hash, options)
36
38
 
37
- hash
39
+ hash
40
+ end
38
41
  end
39
-
40
42
  end
41
43
  end
42
-
@@ -1,10 +1,11 @@
1
- module ClientSideValidations::ActiveModel
2
- module Presence
3
- private
1
+ module ClientSideValidations
2
+ module ActiveModel
3
+ module Presence
4
+ private
4
5
 
5
- def message_type
6
- :blank
6
+ def message_type
7
+ :blank
8
+ end
7
9
  end
8
10
  end
9
11
  end
10
-
@@ -2,10 +2,10 @@ require 'client_side_validations/active_model'
2
2
  require 'client_side_validations/middleware'
3
3
  require 'client_side_validations/active_record/middleware'
4
4
 
5
- %w{uniqueness}.each do |validator|
5
+ %w(uniqueness).each do |validator|
6
6
  require "client_side_validations/active_record/#{validator}"
7
7
  validator.capitalize!
8
- eval "ActiveRecord::Validations::#{validator}Validator.send(:include, ClientSideValidations::ActiveRecord::#{validator})"
8
+ ActiveRecord::Validations.const_get("#{validator}Validator").send :include, ClientSideValidations::ActiveRecord.const_get(validator)
9
9
  end
10
10
 
11
11
  ActiveRecord::Base.send(:include, ClientSideValidations::ActiveModel::Validations)
@@ -1,51 +1,53 @@
1
- module ClientSideValidations::ActiveRecord
2
- class Middleware
1
+ module ClientSideValidations
2
+ module ActiveRecord
3
+ class Middleware
4
+ def self.class?(klass)
5
+ klass.abstract_class.blank? && klass < ::ActiveRecord::Base
6
+ end
3
7
 
4
- def self.is_class?(klass)
5
- klass.abstract_class.blank? && klass < ::ActiveRecord::Base
6
- end
8
+ def self.unique?(klass, attribute, value, params)
9
+ klass = find_topmost_superclass(klass)
10
+ column = klass.columns_hash[attribute.to_s]
11
+ value = type_cast_value(column, value)
12
+ value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if value.is_a?(String)
7
13
 
8
- def self.is_unique?(klass, attribute, value, params)
9
- klass = find_topmost_superclass(klass)
10
- value = type_cast_value(klass, attribute, value)
11
- column = klass.columns_hash[attribute.to_s]
12
- value = column.limit ? value.to_s.mb_chars[0, column.limit] : value.to_s if column.text?
13
-
14
- t = klass.arel_table
15
-
16
- sql = []
17
- if params[:case_sensitive] == 'true'
18
- sql << 'BINARY' if t.engine.connection.adapter_name =~ /^mysql/i
19
- sql << t[attribute].eq(value).to_sql
20
- else
21
- escaped_value = value.gsub(/[%_]/, '\\\\\0')
22
- sql << "#{t[attribute].matches(escaped_value).to_sql} ESCAPE '\\'"
23
- end
14
+ t = klass.arel_table
24
15
 
25
- sql << "AND #{t[klass.primary_key].not_eq(params[:id]).to_sql}" if params[:id]
16
+ sql = []
17
+ if params[:case_sensitive] == 'true'
18
+ sql << 'BINARY' if t.engine.connection.adapter_name =~ /^mysql/i
19
+ sql << t[attribute].eq(value).to_sql
20
+ else
21
+ escaped_value = value.gsub(/[%_]/, '\\\\\0')
22
+ sql << "#{t[attribute].matches(escaped_value).to_sql} ESCAPE '\\'"
23
+ end
26
24
 
27
- (params[:scope] || {}).each do |attribute, value|
28
- value = type_cast_value(klass, attribute, value)
29
- sql << "AND #{t[attribute].eq(value).to_sql}"
30
- end
25
+ sql << "AND #{t[klass.primary_key].not_eq(params[:id]).to_sql}" if params[:id]
31
26
 
32
- relation = Arel::Nodes::SqlLiteral.new(sql.join(' '))
33
- !klass.where(relation).exists?
34
- end
27
+ (params[:scope] || {}).each do |scope_attribute, scope_value|
28
+ scope_value = type_cast_value(klass.columns_hash[scope_attribute], scope_value)
29
+ sql << "AND #{t[scope_attribute].eq(scope_value).to_sql}"
30
+ end
35
31
 
36
- private
32
+ relation = Arel::Nodes::SqlLiteral.new(sql.join(' '))
33
+ !klass.where(relation).exists?
34
+ end
37
35
 
38
- def self.type_cast_value(klass, attribute, value)
39
- klass.columns_hash[attribute].type_cast(value)
40
- end
36
+ def self.type_cast_value(column, value)
37
+ if column.respond_to?(:type_cast)
38
+ column.type_cast(value)
39
+ else
40
+ column.type_cast_from_database(value)
41
+ end
42
+ end
41
43
 
42
- def self.find_topmost_superclass(klass)
43
- if is_class?(klass.superclass)
44
- find_topmost_superclass(klass.superclass)
45
- else
46
- klass
44
+ def self.find_topmost_superclass(klass)
45
+ if class?(klass.superclass)
46
+ find_topmost_superclass(klass.superclass)
47
+ else
48
+ klass
49
+ end
47
50
  end
48
51
  end
49
-
50
52
  end
51
53
  end
@@ -1,32 +1,33 @@
1
- module ClientSideValidations::ActiveRecord
2
- module Uniqueness
3
- def client_side_hash(model, attribute, force = nil)
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
- hash[:allow_blank] = true if options[:allow_blank]
1
+ module ClientSideValidations
2
+ module ActiveRecord
3
+ module Uniqueness
4
+ def client_side_hash(model, attribute, _force = nil)
5
+ hash = {}
6
+ hash[:message] = model.errors.generate_message(attribute, message_type, options.except(:scope))
7
+ hash[:case_sensitive] = options[:case_sensitive]
8
+ hash[:id] = model.id unless model.new_record?
9
+ hash[:allow_blank] = true if options[:allow_blank]
9
10
 
10
- if options.key?(:client_validations) && options[:client_validations].key?(:class)
11
- hash[:class] = options[:client_validations][:class].underscore
12
- elsif model.class.name.demodulize != model.class.name
13
- hash[:class] = model.class.name.underscore
14
- end
11
+ if options.key?(:client_validations) && options[:client_validations].key?(:class)
12
+ hash[:class] = options[:client_validations][:class].underscore
13
+ elsif model.class.name.demodulize != model.class.name
14
+ hash[:class] = model.class.name.underscore
15
+ end
15
16
 
16
- if options.key?(:scope) && options[:scope].present?
17
- hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
18
- scope_hash.merge!(scope_item => model.send(scope_item))
17
+ if options.key?(:scope) && options[:scope].present?
18
+ hash[:scope] = Array.wrap(options[:scope]).inject({}) do |scope_hash, scope_item|
19
+ scope_hash.merge!(scope_item => model.send(scope_item))
20
+ end
19
21
  end
20
- end
21
22
 
22
- hash
23
- end
23
+ hash
24
+ end
24
25
 
25
- private
26
+ private
26
27
 
27
- def message_type
28
- :taken
28
+ def message_type
29
+ :taken
30
+ end
29
31
  end
30
32
  end
31
33
  end
32
-
@@ -6,7 +6,7 @@ module ClientSideValidations
6
6
  attr_accessor :root_path
7
7
  end
8
8
 
9
- self.disabled_validators = []
9
+ self.disabled_validators = [:uniqueness]
10
10
  self.number_format_with_locale = false
11
11
  self.root_path = nil
12
12
  end
@@ -1,5 +1,5 @@
1
1
  class Range
2
- def as_json(options = nil)
2
+ def as_json(*)
3
3
  [first, last]
4
4
  end
5
5
 
@@ -7,4 +7,3 @@ class Range
7
7
  as_json(options).inspect
8
8
  end
9
9
  end
10
-
@@ -1,13 +1,15 @@
1
+ require 'js_regex'
2
+
1
3
  class Regexp
2
- def as_json(options = nil)
3
- Regexp.new inspect.sub('\\A','^').sub('\\Z','$').sub('\\z','$').sub(/^\//,'').sub(/\/[a-z]*$/,'').gsub(/\(\?#.+\)/, '').gsub(/\(\?-\w+:/,'(').gsub(/\s/,''), self.options & 5
4
+ def as_json(*)
5
+ JsRegex.new(self).to_h
4
6
  end
5
7
 
6
8
  def to_json(options = nil)
7
- as_json(options).inspect
9
+ as_json(options)
8
10
  end
9
11
 
10
- def encode_json(encoder)
12
+ def encode_json(_encoder)
11
13
  inspect
12
14
  end
13
15
  end
@@ -3,4 +3,3 @@ module ClientSideValidations
3
3
  config.app_middleware.use ClientSideValidations::Middleware::Validators
4
4
  end
5
5
  end
6
-
@@ -1,12 +1,11 @@
1
1
  module ClientSideValidations
2
2
  module Generators
3
- Assets = []
3
+ ASSETS = []
4
4
 
5
5
  def self.register_assets(klass)
6
- Assets.push(*klass.assets)
6
+ ASSETS.push(*klass.assets)
7
7
  end
8
8
  end
9
9
  end
10
10
 
11
11
  require 'client_side_validations/generators/rails_validations'
12
-
@@ -3,8 +3,8 @@ module ClientSideValidations
3
3
  class RailsValidations
4
4
  def self.assets
5
5
  [{
6
- :path => File.expand_path('../../../../vendor/assets/javascripts', __FILE__),
7
- :file => 'rails.validations.js'
6
+ path: File.expand_path('../../../../vendor/assets/javascripts', __FILE__),
7
+ file: 'rails.validations.js'
8
8
  }]
9
9
  end
10
10
 
@@ -12,4 +12,3 @@ module ClientSideValidations
12
12
  end
13
13
  end
14
14
  end
15
-
@@ -1,9 +1,6 @@
1
- # encoding: utf-8
2
-
3
1
  require 'client_side_validations/core_ext'
4
2
 
5
3
  module ClientSideValidations
6
-
7
4
  module Middleware
8
5
  class Validators
9
6
  def initialize(app)
@@ -11,7 +8,8 @@ module ClientSideValidations
11
8
  end
12
9
 
13
10
  def call(env)
14
- if matches = /\A\/validators\/(\w+)\z/.match(env['PATH_INFO'])
11
+ matches = %r{\A/validators/(\w+)\z}.match(env['PATH_INFO'])
12
+ if matches
15
13
  process_request(matches.captures.first, env)
16
14
  else
17
15
  @app.call(env)
@@ -19,23 +17,23 @@ module ClientSideValidations
19
17
  end
20
18
 
21
19
  def process_request(validation, env)
22
- if disabled_validators.include?(validation.downcase)
20
+ if disabled_validators.include?(validation)
23
21
  error_resp
24
22
  else
25
23
  klass_name = validation.camelize
26
24
  klass_name = "::ClientSideValidations::Middleware::#{klass_name}"
27
25
  klass_name.constantize.new(env).response
28
26
  end
29
- rescue => e
27
+ rescue
30
28
  error_resp
31
29
  end
32
30
 
33
31
  def disabled_validators
34
- ClientSideValidations::Config.disabled_validators.map { |v| v.to_s.downcase }
32
+ ClientSideValidations::Config.disabled_validators.map(&:to_s)
35
33
  end
36
34
 
37
35
  def error_resp
38
- [500, {'Content-Type' => 'application/json', 'Content-Length' => '0'}, ['']]
36
+ [500, { 'Content-Type' => 'application/json', 'Content-Length' => '0' }, ['']]
39
37
  end
40
38
  end
41
39
 
@@ -51,7 +49,7 @@ module ClientSideValidations
51
49
  end
52
50
 
53
51
  def response
54
- [status, {'Content-Type' => content_type, 'Content-Length' => body.length.to_s}, [body]]
52
+ [status, { 'Content-Type' => content_type, 'Content-Length' => body.length.to_s }, [body]]
55
53
  end
56
54
 
57
55
  def content_type
@@ -60,13 +58,13 @@ module ClientSideValidations
60
58
  end
61
59
 
62
60
  class Uniqueness < Base
63
- IGNORE_PARAMS = %w{case_sensitive id scope}
61
+ IGNORE_PARAMS = %w(case_sensitive id scope)
64
62
  REGISTERED_ORMS = []
65
63
  class NotValidatable < StandardError; end
66
64
 
67
65
  def response
68
66
  begin
69
- if is_unique?
67
+ if unique?
70
68
  self.status = 404
71
69
  self.body = 'true'
72
70
  else
@@ -94,32 +92,29 @@ module ClientSideValidations
94
92
 
95
93
  private
96
94
 
97
- def is_unique?
95
+ def unique?
98
96
  convert_scope_value_from_null_to_nil
99
97
  klass, attribute, value = extract_resources
100
98
  middleware_class = nil
101
99
 
102
100
  unless Array.wrap(klass._validators[attribute.to_sym]).find { |v| v.kind == :uniqueness }
103
- raise NotValidatable
101
+ fail NotValidatable
104
102
  end
105
103
 
106
104
  registered_orms.each do |orm|
107
- if orm.is_class?(klass)
105
+ if orm.class?(klass)
108
106
  middleware_class = orm
109
107
  break
110
108
  end
111
109
  end
112
110
 
113
- middleware_class.is_unique?(klass, attribute, value, request.params)
111
+ middleware_class.unique?(klass, attribute, value, request.params)
114
112
  end
115
113
 
116
114
  def convert_scope_value_from_null_to_nil
117
- if request.params['scope']
118
- request.params['scope'].each do |key, value|
119
- if value == 'null'
120
- request.params['scope'][key] = nil
121
- end
122
- end
115
+ return unless request.params['scope']
116
+ request.params['scope'].each do |key, value|
117
+ request.params['scope'][key] = nil if value == 'null'
123
118
  end
124
119
  end
125
120
 
@@ -153,14 +148,12 @@ module ClientSideValidations
153
148
 
154
149
  def nested?(hash = nil, levels = 0)
155
150
  i = 0
156
- until !(hash.respond_to? :keys)
151
+ while hash.respond_to? :keys
157
152
  hash = hash[hash.keys.first]
158
153
  i += 1
159
154
  end
160
155
  i > levels
161
156
  end
162
-
163
157
  end
164
158
  end
165
159
  end
166
-