activemodel 5.0.7.2 → 5.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +15 -219
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_model.rb +11 -12
  6. data/lib/active_model/attribute_assignment.rb +11 -11
  7. data/lib/active_model/attribute_methods.rb +13 -15
  8. data/lib/active_model/callbacks.rb +19 -20
  9. data/lib/active_model/conversion.rb +12 -3
  10. data/lib/active_model/dirty.rb +14 -14
  11. data/lib/active_model/errors.rb +27 -103
  12. data/lib/active_model/forbidden_attributes_protection.rb +1 -1
  13. data/lib/active_model/gem_version.rb +3 -3
  14. data/lib/active_model/lint.rb +0 -1
  15. data/lib/active_model/model.rb +3 -4
  16. data/lib/active_model/naming.rb +9 -10
  17. data/lib/active_model/secure_password.rb +1 -1
  18. data/lib/active_model/serialization.rb +2 -2
  19. data/lib/active_model/serializers/json.rb +2 -2
  20. data/lib/active_model/translation.rb +2 -3
  21. data/lib/active_model/type.rb +15 -19
  22. data/lib/active_model/type/big_integer.rb +4 -4
  23. data/lib/active_model/type/binary.rb +1 -1
  24. data/lib/active_model/type/boolean.rb +20 -9
  25. data/lib/active_model/type/date.rb +25 -25
  26. data/lib/active_model/type/date_time.rb +21 -21
  27. data/lib/active_model/type/decimal.rb +35 -39
  28. data/lib/active_model/type/float.rb +17 -8
  29. data/lib/active_model/type/helpers.rb +4 -4
  30. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +2 -2
  31. data/lib/active_model/type/helpers/mutable.rb +2 -2
  32. data/lib/active_model/type/helpers/numeric.rb +18 -17
  33. data/lib/active_model/type/helpers/time_value.rb +23 -23
  34. data/lib/active_model/type/immutable_string.rb +9 -8
  35. data/lib/active_model/type/integer.rb +23 -21
  36. data/lib/active_model/type/registry.rb +12 -8
  37. data/lib/active_model/type/string.rb +1 -6
  38. data/lib/active_model/type/time.rb +15 -11
  39. data/lib/active_model/type/value.rb +6 -6
  40. data/lib/active_model/validations.rb +9 -12
  41. data/lib/active_model/validations/absence.rb +1 -1
  42. data/lib/active_model/validations/acceptance.rb +41 -40
  43. data/lib/active_model/validations/callbacks.rb +4 -7
  44. data/lib/active_model/validations/clusivity.rb +7 -7
  45. data/lib/active_model/validations/confirmation.rb +15 -16
  46. data/lib/active_model/validations/exclusion.rb +1 -2
  47. data/lib/active_model/validations/format.rb +24 -24
  48. data/lib/active_model/validations/inclusion.rb +1 -2
  49. data/lib/active_model/validations/length.rb +6 -42
  50. data/lib/active_model/validations/numericality.rb +3 -11
  51. data/lib/active_model/validations/presence.rb +1 -2
  52. data/lib/active_model/validations/validates.rb +6 -6
  53. data/lib/active_model/validations/with.rb +4 -2
  54. data/lib/active_model/validator.rb +5 -6
  55. data/lib/active_model/version.rb +1 -1
  56. metadata +8 -11
  57. data/lib/active_model/test_case.rb +0 -4
  58. data/lib/active_model/type/decimal_without_scale.rb +0 -11
  59. data/lib/active_model/type/text.rb +0 -11
  60. data/lib/active_model/type/unsigned_integer.rb +0 -15
@@ -23,14 +23,12 @@ module ActiveModel
23
23
  included do
24
24
  include ActiveSupport::Callbacks
25
25
  define_callbacks :validation,
26
- terminator: deprecated_false_terminator,
27
26
  skip_after_callbacks_if_terminated: true,
28
27
  scope: [:kind, :name]
29
28
  end
30
29
 
31
30
  module ClassMethods
32
- # Defines a callback that will get called right before validation
33
- # happens.
31
+ # Defines a callback that will get called right before validation.
34
32
  #
35
33
  # class Person
36
34
  # include ActiveModel::Validations
@@ -65,8 +63,7 @@ module ActiveModel
65
63
  set_callback(:validation, :before, *args, &block)
66
64
  end
67
65
 
68
- # Defines a callback that will get called right after validation
69
- # happens.
66
+ # Defines a callback that will get called right after validation.
70
67
  #
71
68
  # class Person
72
69
  # include ActiveModel::Validations
@@ -106,10 +103,10 @@ module ActiveModel
106
103
  end
107
104
  end
108
105
 
109
- protected
106
+ private
110
107
 
111
108
  # Overwrite run validations to include callbacks.
112
- def run_validations! #:nodoc:
109
+ def run_validations!
113
110
  _run_validation_callbacks { super }
114
111
  end
115
112
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/range'
1
+ require "active_support/core_ext/range"
2
2
 
3
3
  module ActiveModel
4
4
  module Validations
@@ -16,12 +16,12 @@ module ActiveModel
16
16
 
17
17
  def include?(record, value)
18
18
  members = if delimiter.respond_to?(:call)
19
- delimiter.call(record)
20
- elsif delimiter.respond_to?(:to_sym)
21
- record.send(delimiter)
22
- else
23
- delimiter
24
- end
19
+ delimiter.call(record)
20
+ elsif delimiter.respond_to?(:to_sym)
21
+ record.send(delimiter)
22
+ else
23
+ delimiter
24
+ end
25
25
 
26
26
  members.send(inclusion_method(members), value)
27
27
  end
@@ -1,5 +1,4 @@
1
1
  module ActiveModel
2
-
3
2
  module Validations
4
3
  class ConfirmationValidator < EachValidator # :nodoc:
5
4
  def initialize(options)
@@ -17,23 +16,23 @@ module ActiveModel
17
16
  end
18
17
 
19
18
  private
20
- def setup!(klass)
21
- klass.send(:attr_reader, *attributes.map do |attribute|
22
- :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
23
- end.compact)
19
+ def setup!(klass)
20
+ klass.send(:attr_reader, *attributes.map do |attribute|
21
+ :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation")
22
+ end.compact)
24
23
 
25
- klass.send(:attr_writer, *attributes.map do |attribute|
26
- :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
27
- end.compact)
28
- end
24
+ klass.send(:attr_writer, *attributes.map do |attribute|
25
+ :"#{attribute}_confirmation" unless klass.method_defined?(:"#{attribute}_confirmation=")
26
+ end.compact)
27
+ end
29
28
 
30
- def confirmation_value_equal?(record, attribute, value, confirmed)
31
- if !options[:case_sensitive] && value.is_a?(String)
32
- value.casecmp(confirmed) == 0
33
- else
34
- value == confirmed
29
+ def confirmation_value_equal?(record, attribute, value, confirmed)
30
+ if !options[:case_sensitive] && value.is_a?(String)
31
+ value.casecmp(confirmed) == 0
32
+ else
33
+ value == confirmed
34
+ end
35
35
  end
36
- end
37
36
  end
38
37
 
39
38
  module HelperMethods
@@ -70,7 +69,7 @@ module ActiveModel
70
69
  #
71
70
  # There is also a list of default options supported by every validator:
72
71
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
73
- # See <tt>ActiveModel::Validation#validates</tt> for more information
72
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
74
73
  def validates_confirmation_of(*attr_names)
75
74
  validates_with ConfirmationValidator, _merge_attributes(attr_names)
76
75
  end
@@ -1,7 +1,6 @@
1
1
  require "active_model/validations/clusivity"
2
2
 
3
3
  module ActiveModel
4
-
5
4
  module Validations
6
5
  class ExclusionValidator < EachValidator # :nodoc:
7
6
  include Clusivity
@@ -39,7 +38,7 @@ module ActiveModel
39
38
  #
40
39
  # There is also a list of default options supported by every validator:
41
40
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
42
- # See <tt>ActiveModel::Validation#validates</tt> for more information
41
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
43
42
  def validates_exclusion_of(*attr_names)
44
43
  validates_with ExclusionValidator, _merge_attributes(attr_names)
45
44
  end
@@ -1,5 +1,5 @@
1
- module ActiveModel
2
1
 
2
+ module ActiveModel
3
3
  module Validations
4
4
  class FormatValidator < EachValidator # :nodoc:
5
5
  def validate_each(record, attribute, value)
@@ -8,7 +8,7 @@ module ActiveModel
8
8
  record_error(record, attribute, :with, value) if value.to_s !~ regexp
9
9
  elsif options[:without]
10
10
  regexp = option_call(record, :without)
11
- record_error(record, attribute, :without, value) if value.to_s =~ regexp
11
+ record_error(record, attribute, :without, value) if regexp.match?(value.to_s)
12
12
  end
13
13
  end
14
14
 
@@ -23,33 +23,33 @@ module ActiveModel
23
23
 
24
24
  private
25
25
 
26
- def option_call(record, name)
27
- option = options[name]
28
- option.respond_to?(:call) ? option.call(record) : option
29
- end
26
+ def option_call(record, name)
27
+ option = options[name]
28
+ option.respond_to?(:call) ? option.call(record) : option
29
+ end
30
30
 
31
- def record_error(record, attribute, name, value)
32
- record.errors.add(attribute, :invalid, options.except(name).merge!(value: value))
33
- end
31
+ def record_error(record, attribute, name, value)
32
+ record.errors.add(attribute, :invalid, options.except(name).merge!(value: value))
33
+ end
34
34
 
35
- def check_options_validity(name)
36
- if option = options[name]
37
- if option.is_a?(Regexp)
38
- if options[:multiline] != true && regexp_using_multiline_anchors?(option)
39
- raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
40
- "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
41
- ":multiline => true option?"
35
+ def check_options_validity(name)
36
+ if option = options[name]
37
+ if option.is_a?(Regexp)
38
+ if options[:multiline] != true && regexp_using_multiline_anchors?(option)
39
+ raise ArgumentError, "The provided regular expression is using multiline anchors (^ or $), " \
40
+ "which may present a security risk. Did you mean to use \\A and \\z, or forgot to add the " \
41
+ ":multiline => true option?"
42
+ end
43
+ elsif !option.respond_to?(:call)
44
+ raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
42
45
  end
43
- elsif !option.respond_to?(:call)
44
- raise ArgumentError, "A regular expression or a proc or lambda must be supplied as :#{name}"
45
46
  end
46
47
  end
47
- end
48
48
 
49
- def regexp_using_multiline_anchors?(regexp)
50
- source = regexp.source
51
- source.start_with?("^") || (source.end_with?("$") && !source.end_with?("\\$"))
52
- end
49
+ def regexp_using_multiline_anchors?(regexp)
50
+ source = regexp.source
51
+ source.start_with?("^") || (source.end_with?("$") && !source.end_with?("\\$"))
52
+ end
53
53
  end
54
54
 
55
55
  module HelperMethods
@@ -104,7 +104,7 @@ module ActiveModel
104
104
  #
105
105
  # There is also a list of default options supported by every validator:
106
106
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
107
- # See <tt>ActiveModel::Validation#validates</tt> for more information
107
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
108
108
  def validates_format_of(*attr_names)
109
109
  validates_with FormatValidator, _merge_attributes(attr_names)
110
110
  end
@@ -1,7 +1,6 @@
1
1
  require "active_model/validations/clusivity"
2
2
 
3
3
  module ActiveModel
4
-
5
4
  module Validations
6
5
  class InclusionValidator < EachValidator # :nodoc:
7
6
  include Clusivity
@@ -37,7 +36,7 @@ module ActiveModel
37
36
  #
38
37
  # There is also a list of default options supported by every validator:
39
38
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
40
- # See <tt>ActiveModel::Validation#validates</tt> for more information
39
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
41
40
  def validates_inclusion_of(*attr_names)
42
41
  validates_with InclusionValidator, _merge_attributes(attr_names)
43
42
  end
@@ -1,12 +1,10 @@
1
- require "active_support/core_ext/string/strip"
2
-
3
1
  module ActiveModel
4
2
  module Validations
5
3
  class LengthValidator < EachValidator # :nodoc:
6
4
  MESSAGES = { is: :wrong_length, minimum: :too_short, maximum: :too_long }.freeze
7
5
  CHECKS = { is: :==, minimum: :>=, maximum: :<= }.freeze
8
6
 
9
- RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :tokenizer, :too_short, :too_long]
7
+ RESERVED_OPTIONS = [:minimum, :maximum, :within, :is, :too_short, :too_long]
10
8
 
11
9
  def initialize(options)
12
10
  if range = (options.delete(:in) || options.delete(:within))
@@ -18,27 +16,6 @@ module ActiveModel
18
16
  options[:minimum] = 1
19
17
  end
20
18
 
21
- if options[:tokenizer]
22
- ActiveSupport::Deprecation.warn(<<-EOS.strip_heredoc)
23
- The `:tokenizer` option is deprecated, and will be removed in Rails 5.1.
24
- You can achieve the same functionality by defining an instance method
25
- with the value that you want to validate the length of. For example,
26
-
27
- validates_length_of :essay, minimum: 100,
28
- tokenizer: ->(str) { str.scan(/\w+/) }
29
-
30
- should be written as
31
-
32
- validates_length_of :words_in_essay, minimum: 100
33
-
34
- private
35
-
36
- def words_in_essay
37
- essay.scan(/\w+/)
38
- end
39
- EOS
40
- end
41
-
42
19
  super
43
20
  end
44
21
 
@@ -46,7 +23,7 @@ module ActiveModel
46
23
  keys = CHECKS.keys & options.keys
47
24
 
48
25
  if keys.empty?
49
- raise ArgumentError, 'Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option.'
26
+ raise ArgumentError, "Range unspecified. Specify the :in, :within, :maximum, :minimum, or :is option."
50
27
  end
51
28
 
52
29
  keys.each do |key|
@@ -59,7 +36,6 @@ module ActiveModel
59
36
  end
60
37
 
61
38
  def validate_each(record, attribute, value)
62
- value = tokenize(record, value)
63
39
  value_length = value.respond_to?(:length) ? value.length : value.to_s.length
64
40
  errors_options = options.except(*RESERVED_OPTIONS)
65
41
 
@@ -80,24 +56,12 @@ module ActiveModel
80
56
  end
81
57
 
82
58
  private
83
- def tokenize(record, value)
84
- tokenizer = options[:tokenizer]
85
- if tokenizer && value.kind_of?(String)
86
- if tokenizer.kind_of?(Proc)
87
- tokenizer.call(value)
88
- elsif record.respond_to?(tokenizer)
89
- record.send(tokenizer, value)
90
- end
91
- end || value
92
- end
93
-
94
- def skip_nil_check?(key)
95
- key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil?
96
- end
59
+ def skip_nil_check?(key)
60
+ key == :maximum && options[:allow_nil].nil? && options[:allow_blank].nil?
61
+ end
97
62
  end
98
63
 
99
64
  module HelperMethods
100
-
101
65
  # Validates that the specified attributes match the length restrictions
102
66
  # supplied. Only one constraint option can be used at a time apart from
103
67
  # +:minimum+ and +:maximum+ that can be combined together:
@@ -146,7 +110,7 @@ module ActiveModel
146
110
  #
147
111
  # There is also a list of default options supported by every validator:
148
112
  # +:if+, +:unless+, +:on+ and +:strict+.
149
- # See <tt>ActiveModel::Validation#validates</tt> for more information
113
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
150
114
  def validates_length_of(*attr_names)
151
115
  validates_with LengthValidator, _merge_attributes(attr_names)
152
116
  end
@@ -1,5 +1,4 @@
1
1
  module ActiveModel
2
-
3
2
  module Validations
4
3
  class NumericalityValidator < EachValidator # :nodoc:
5
4
  CHECKS = { greater_than: :>, greater_than_or_equal_to: :>=,
@@ -27,8 +26,6 @@ module ActiveModel
27
26
  raw_value = value
28
27
  end
29
28
 
30
- return if options[:allow_nil] && raw_value.nil?
31
-
32
29
  unless is_number?(raw_value)
33
30
  record.errors.add(attr_name, :not_a_number, filtered_options(raw_value))
34
31
  return
@@ -39,9 +36,7 @@ module ActiveModel
39
36
  return
40
37
  end
41
38
 
42
- if raw_value.is_a?(Numeric)
43
- value = raw_value
44
- else
39
+ unless raw_value.is_a?(Numeric)
45
40
  value = parse_raw_value_as_a_number(raw_value)
46
41
  end
47
42
 
@@ -66,7 +61,7 @@ module ActiveModel
66
61
  end
67
62
  end
68
63
 
69
- protected
64
+ private
70
65
 
71
66
  def is_number?(raw_value)
72
67
  !parse_raw_value_as_a_number(raw_value).nil?
@@ -75,7 +70,6 @@ module ActiveModel
75
70
  end
76
71
 
77
72
  def parse_raw_value_as_a_number(raw_value)
78
- return raw_value.to_i if is_integer?(raw_value)
79
73
  Kernel.Float(raw_value) if raw_value !~ /\A0[xX]/
80
74
  end
81
75
 
@@ -100,8 +94,6 @@ module ActiveModel
100
94
  end
101
95
  end
102
96
 
103
- private
104
-
105
97
  def record_attribute_changed_in_place?(record, attr_name)
106
98
  record.respond_to?(:attribute_changed_in_place?) &&
107
99
  record.attribute_changed_in_place?(attr_name.to_s)
@@ -142,7 +134,7 @@ module ActiveModel
142
134
  #
143
135
  # There is also a list of default options supported by every validator:
144
136
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+ .
145
- # See <tt>ActiveModel::Validation#validates</tt> for more information
137
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
146
138
  #
147
139
  # The following checks can also be supplied with a proc or a symbol which
148
140
  # corresponds to a method:
@@ -1,6 +1,5 @@
1
1
 
2
2
  module ActiveModel
3
-
4
3
  module Validations
5
4
  class PresenceValidator < EachValidator # :nodoc:
6
5
  def validate_each(record, attr_name, value)
@@ -30,7 +29,7 @@ module ActiveModel
30
29
  #
31
30
  # There is also a list of default options supported by every validator:
32
31
  # +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
33
- # See <tt>ActiveModel::Validation#validates</tt> for more information
32
+ # See <tt>ActiveModel::Validations#validates</tt> for more information
34
33
  def validates_presence_of(*attr_names)
35
34
  validates_with PresenceValidator, _merge_attributes(attr_names)
36
35
  end
@@ -1,4 +1,4 @@
1
- require 'active_support/core_ext/hash/slice'
1
+ require "active_support/core_ext/hash/slice"
2
2
 
3
3
  module ActiveModel
4
4
  module Validations
@@ -72,7 +72,7 @@ module ActiveModel
72
72
  # There is also a list of options that could be used along with validators:
73
73
  #
74
74
  # * <tt>:on</tt> - Specifies the contexts where this validation is active.
75
- # Runs in all validation contexts by default (nil). You can pass a symbol
75
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
76
76
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
77
77
  # <tt>on: :custom_validation_context</tt> or
78
78
  # <tt>on: [:create, :custom_validation_context]</tt>)
@@ -115,7 +115,7 @@ module ActiveModel
115
115
  key = "#{key.to_s.camelize}Validator"
116
116
 
117
117
  begin
118
- validator = key.include?('::'.freeze) ? key.constantize : const_get(key)
118
+ validator = key.include?("::".freeze) ? key.constantize : const_get(key)
119
119
  rescue NameError
120
120
  raise ArgumentError, "Unknown validator: '#{key}'"
121
121
  end
@@ -148,15 +148,15 @@ module ActiveModel
148
148
  validates(*(attributes << options))
149
149
  end
150
150
 
151
- protected
151
+ private
152
152
 
153
153
  # When creating custom validators, it might be useful to be able to specify
154
154
  # additional default keys. This can be done by overwriting this method.
155
- def _validates_default_keys # :nodoc:
155
+ def _validates_default_keys
156
156
  [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
157
157
  end
158
158
 
159
- def _parse_validates_options(options) # :nodoc:
159
+ def _parse_validates_options(options)
160
160
  case options
161
161
  when TrueClass
162
162
  {}
@@ -1,3 +1,5 @@
1
+ require "active_support/core_ext/array/extract_options"
2
+
1
3
  module ActiveModel
2
4
  module Validations
3
5
  class WithValidator < EachValidator # :nodoc:
@@ -43,7 +45,7 @@ module ActiveModel
43
45
  #
44
46
  # Configuration options:
45
47
  # * <tt>:on</tt> - Specifies the contexts where this validation is active.
46
- # Runs in all validation contexts by default (nil). You can pass a symbol
48
+ # Runs in all validation contexts by default +nil+. You can pass a symbol
47
49
  # or an array of symbols. (e.g. <tt>on: :create</tt> or
48
50
  # <tt>on: :custom_validation_context</tt> or
49
51
  # <tt>on: [:create, :custom_validation_context]</tt>)
@@ -59,7 +61,7 @@ module ActiveModel
59
61
  # The method, proc or string should return or evaluate to a +true+ or
60
62
  # +false+ value.
61
63
  # * <tt>:strict</tt> - Specifies whether validation should be strict.
62
- # See <tt>ActiveModel::Validation#validates!</tt> for more information.
64
+ # See <tt>ActiveModel::Validations#validates!</tt> for more information.
63
65
  #
64
66
  # If you pass any additional configuration options, they will be passed
65
67
  # to the class and available as +options+: