can_has_validations 0.5.1 → 0.6.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8eada0f5dd41202696bbab1b493bb017489452ed29459b3f48925236eaec01d
4
- data.tar.gz: 357ffbc02deb80c773b0b0f604c8dc0f773d7fd62da030f7fa03299a0fe3ba20
3
+ metadata.gz: 39feb1ba720229383addaf65d761cf38ce5da9545b5e402cf3a9a064523b987a
4
+ data.tar.gz: 8128047f635300ddae1771a1d997f22cb732391d79f4d49bc7c2e47bab2c51a4
5
5
  SHA512:
6
- metadata.gz: d5a8f3386d4e3d420a4492370a77479658557f0d5d97e3f04fc7fe95bb04934a9e23cc4146b6f2be60d20db25a049b8387bc46ee1f6dd6156b175b69a8f598e1
7
- data.tar.gz: 6cfa0fab71ff63d23c0d53c9b3780107b99a0af9a126cc695022613fe6b6b5ff28f68315706cd1153114d2c3e90bfb65401d9e4c99ba6fde8578c02c9982c82c
6
+ metadata.gz: 212be440432bb1ff47193b1948a603138d01e813fd88d0978c8fd8c9ab1d61d39dee23914a1aa0b91abbd955a520b991c609b0a597571e253edfa3242f8006b2
7
+ data.tar.gz: 190a03e36354954c46b9a1b4e45e22197cad6b6819565320446f55fb9e6f6ed3cbfe42d038afd141ba9ca61f087da392c84464636a7c5ce12bea3035c38b01e7
data/README.md CHANGED
@@ -5,6 +5,7 @@ ActiveModel.
5
5
 
6
6
  Validations provided:
7
7
 
8
+ * Array
8
9
  * Email
9
10
  * Existence
10
11
  * Grandparent
@@ -29,6 +30,35 @@ Add it to your `Gemfile`:
29
30
 
30
31
 
31
32
 
33
+ ## Array validator ##
34
+
35
+ Many database engines allow for arrays of attributes. This validates each
36
+ member element of those arrays.
37
+
38
+ It is able to use most existing validators that themselves work on individual
39
+ attribute values (including standard Rails validators, others that are part of
40
+ this gem, and likely many from other gems too).
41
+
42
+ By default, it will stop validation of an array attribute after the first error
43
+ per validator, regardless of how many elements might fail validation. This both
44
+ improves performance as well as avoids producing a large number of duplicate
45
+ error messages. Add `multiple_errors: true` on `:array` or any individual
46
+ sub-validator to instead return all errors (useful if each error message will
47
+ vary based on the element's value).
48
+
49
+ validates :tags,
50
+ array: {
51
+ format: /\A[^aeiou]*\z/,
52
+ length: 5..10
53
+ }
54
+
55
+ validates :permissions,
56
+ array: {
57
+ multiple_errors: true,
58
+ format: /\A[^aeiou]*\z/
59
+ }
60
+
61
+
32
62
  ## Email validator ##
33
63
 
34
64
  Ensures an attribute is generally formatted as an email. It uses a basic regex
@@ -51,7 +81,7 @@ avoid any potential conflicts).
51
81
  Mongoid 3 and 4 also exhibit the same behavior as Rails 4, even under Rails 3,
52
82
  so this is useful with Mongoid as well.
53
83
 
54
- validates :name, presence: true
84
+ validates :name, existence: true
55
85
 
56
86
 
57
87
  ## Grandparent validator ##
@@ -1,4 +1,6 @@
1
- %w(email existence grandparent hostname ordering url write_once).each do |validator|
1
+ require 'active_model/validations'
2
+
3
+ %w(array email existence grandparent hostname ordering url write_once).each do |validator|
2
4
  require "can_has_validations/validators/#{validator}_validator"
3
5
  end
4
6
 
@@ -0,0 +1,104 @@
1
+ # validates each member element of an array attribute
2
+ #
3
+ # by default will allow only the first error per validator, regardless of how
4
+ # many elements might fail validation. this improves performance as well as
5
+ # averting a large number of repeating error messages.
6
+ # use multiple_errors: true on :array or a single sub-validator to enable the
7
+ # full set of errors. this is potentially useful if each error message will
8
+ # vary based upon the array element's contents.
9
+ #
10
+ # usage:
11
+ # validates :tags,
12
+ # array: {
13
+ # format: /\A[^aeiou]*\z/,
14
+ # length: 5..10
15
+ # }
16
+ #
17
+ # validates :permissions,
18
+ # array: {
19
+ # multiple_errors: true,
20
+ # format: /\A[^aeiou]*\z/
21
+ # }
22
+
23
+ module ActiveModel
24
+ module Validations
25
+ class ArrayValidator < ActiveModel::EachValidator
26
+ attr_reader :validators
27
+
28
+ def initialize(options)
29
+ record_class = options[:class]
30
+ super
31
+ record_class.prepend DefaultKeys
32
+
33
+ defaults = @options.dup
34
+ validations = defaults.slice!(*record_class.send(:_validates_default_keys), :attributes)
35
+
36
+ raise ArgumentError, "You need to supply at least one array validation" if validations.empty?
37
+
38
+ defaults[:attributes] = attributes
39
+
40
+ @validators = validations.map do |key, options|
41
+ next unless options
42
+ key = "#{key.to_s.camelize}Validator"
43
+
44
+ begin
45
+ klass = key.include?("::".freeze) ? key.constantize : record_class.const_get(key)
46
+ rescue NameError
47
+ raise ArgumentError, "Unknown validator: '#{key}'"
48
+ end
49
+
50
+ validator = klass.new(defaults.merge(_parse_validates_options(options)))
51
+ end
52
+ end
53
+
54
+ def validate_each(record, attribute, array_values)
55
+ @validators.each do |validator|
56
+ error_count = count_errors(record)
57
+
58
+ Array(array_values).each do |value|
59
+ validator.validate_each(record, attribute, value)
60
+
61
+ # to avoid repeating error messages, stop after a single error
62
+ unless validator.options[:multiple_errors]
63
+ break if error_count != count_errors(record)
64
+ end
65
+ end
66
+ end
67
+ end
68
+
69
+
70
+ private
71
+
72
+ def count_errors(record)
73
+ # more efficient than calling record.errors.size
74
+ record.errors.messages.sum{|key, val| val.blank? ? 0 : val.size }
75
+ end
76
+
77
+ def _parse_validates_options(options)
78
+ case options
79
+ when TrueClass
80
+ {}
81
+ when Hash
82
+ options
83
+ when Range, Array
84
+ { in: options }
85
+ else
86
+ { with: options }
87
+ end
88
+ end
89
+
90
+
91
+ module DefaultKeys
92
+ private
93
+
94
+ # When creating custom validators, it might be useful to be able to specify
95
+ # additional default keys. This can be done by overwriting this method.
96
+ def _validates_default_keys
97
+ super + [:multiple_errors]
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
@@ -1,3 +1,3 @@
1
1
  module CanHasValidations
2
- VERSION = '0.5.1'
2
+ VERSION = '0.6.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: can_has_validations
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thomas morgan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-05-18 00:00:00.000000000 Z
11
+ date: 2018-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -56,12 +56,12 @@ files:
56
56
  - Rakefile
57
57
  - lib/can_has_validations.rb
58
58
  - lib/can_has_validations/locale/en.yml
59
+ - lib/can_has_validations/validators/array_validator.rb
59
60
  - lib/can_has_validations/validators/email_validator.rb
60
61
  - lib/can_has_validations/validators/existence_validator.rb
61
62
  - lib/can_has_validations/validators/grandparent_validator.rb
62
63
  - lib/can_has_validations/validators/hostname_validator.rb
63
64
  - lib/can_has_validations/validators/ordering_validator.rb
64
- - lib/can_has_validations/validators/safe_uniqueness_validator.rb
65
65
  - lib/can_has_validations/validators/url_validator.rb
66
66
  - lib/can_has_validations/validators/write_once_validator.rb
67
67
  - lib/can_has_validations/version.rb
@@ -1,15 +0,0 @@
1
- # better behaved version of the uniqueness validator
2
- # Difference is it doesn't puke if the foreign_key is an invalid type (for
3
- # example, an invalid string being provided for UUID type key). Instead,
4
- # returns an error about being unable to find the key value.
5
- # eg: validates :user_id, safe_uniqueness: true
6
-
7
- class SafeUniquenessValidator < ActiveRecord::Validations::UniquenessValidator
8
- def validate_each(record, attribute, value)
9
- record.transaction(requires_new: true) do
10
- super
11
- end
12
- rescue ActiveRecord::StatementInvalid
13
- record.errors.add(attribute, "%{attribute} %{value} not found", options.except(:case_sensitive, :scope).merge(value: value))
14
- end
15
- end