activemodel 4.2.11.3 → 5.0.7.2

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +149 -56
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +8 -16
  5. data/lib/active_model/attribute_assignment.rb +52 -0
  6. data/lib/active_model/attribute_methods.rb +16 -16
  7. data/lib/active_model/callbacks.rb +3 -3
  8. data/lib/active_model/conversion.rb +5 -5
  9. data/lib/active_model/dirty.rb +41 -40
  10. data/lib/active_model/errors.rb +175 -68
  11. data/lib/active_model/forbidden_attributes_protection.rb +3 -2
  12. data/lib/active_model/gem_version.rb +5 -5
  13. data/lib/active_model/lint.rb +32 -28
  14. data/lib/active_model/locale/en.yml +2 -1
  15. data/lib/active_model/model.rb +3 -4
  16. data/lib/active_model/naming.rb +5 -4
  17. data/lib/active_model/secure_password.rb +2 -9
  18. data/lib/active_model/serialization.rb +36 -9
  19. data/lib/active_model/type/big_integer.rb +13 -0
  20. data/lib/active_model/type/binary.rb +50 -0
  21. data/lib/active_model/type/boolean.rb +21 -0
  22. data/lib/active_model/type/date.rb +54 -0
  23. data/lib/active_model/type/date_time.rb +44 -0
  24. data/lib/active_model/type/decimal.rb +66 -0
  25. data/lib/active_model/type/decimal_without_scale.rb +11 -0
  26. data/lib/active_model/type/float.rb +25 -0
  27. data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +35 -0
  28. data/lib/active_model/type/helpers/mutable.rb +18 -0
  29. data/lib/active_model/type/helpers/numeric.rb +34 -0
  30. data/lib/active_model/type/helpers/time_value.rb +77 -0
  31. data/lib/active_model/type/helpers.rb +4 -0
  32. data/lib/active_model/type/immutable_string.rb +29 -0
  33. data/lib/active_model/type/integer.rb +66 -0
  34. data/lib/active_model/type/registry.rb +64 -0
  35. data/lib/active_model/type/string.rb +24 -0
  36. data/lib/active_model/type/text.rb +11 -0
  37. data/lib/active_model/type/time.rb +42 -0
  38. data/lib/active_model/type/unsigned_integer.rb +15 -0
  39. data/lib/active_model/type/value.rb +116 -0
  40. data/lib/active_model/type.rb +59 -0
  41. data/lib/active_model/validations/absence.rb +1 -1
  42. data/lib/active_model/validations/acceptance.rb +57 -9
  43. data/lib/active_model/validations/callbacks.rb +3 -3
  44. data/lib/active_model/validations/clusivity.rb +4 -3
  45. data/lib/active_model/validations/confirmation.rb +16 -4
  46. data/lib/active_model/validations/exclusion.rb +3 -1
  47. data/lib/active_model/validations/format.rb +1 -1
  48. data/lib/active_model/validations/helper_methods.rb +13 -0
  49. data/lib/active_model/validations/inclusion.rb +3 -3
  50. data/lib/active_model/validations/length.rb +49 -18
  51. data/lib/active_model/validations/numericality.rb +20 -11
  52. data/lib/active_model/validations/validates.rb +1 -1
  53. data/lib/active_model/validations/with.rb +0 -10
  54. data/lib/active_model/validations.rb +34 -1
  55. data/lib/active_model/validator.rb +5 -5
  56. data/lib/active_model/version.rb +1 -1
  57. data/lib/active_model.rb +4 -2
  58. metadata +31 -22
  59. data/lib/active_model/serializers/xml.rb +0 -238
@@ -0,0 +1,18 @@
1
+ module ActiveModel
2
+ module Type
3
+ module Helpers
4
+ module Mutable # :nodoc:
5
+ def cast(value)
6
+ deserialize(serialize(value))
7
+ end
8
+
9
+ # +raw_old_value+ will be the `_before_type_cast` version of the
10
+ # value (likely a string). +new_value+ will be the current, type
11
+ # cast value.
12
+ def changed_in_place?(raw_old_value, new_value)
13
+ raw_old_value != serialize(new_value)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ module ActiveModel
2
+ module Type
3
+ module Helpers
4
+ module Numeric # :nodoc:
5
+ def cast(value)
6
+ value = case value
7
+ when true then 1
8
+ when false then 0
9
+ when ::String then value.presence
10
+ else value
11
+ end
12
+ super(value)
13
+ end
14
+
15
+ def changed?(old_value, _new_value, new_value_before_type_cast) # :nodoc:
16
+ super || number_to_non_number?(old_value, new_value_before_type_cast)
17
+ end
18
+
19
+ private
20
+
21
+ def number_to_non_number?(old_value, new_value_before_type_cast)
22
+ old_value != nil && non_numeric_string?(new_value_before_type_cast)
23
+ end
24
+
25
+ def non_numeric_string?(value)
26
+ # 'wibble'.to_i will give zero, we want to make sure
27
+ # that we aren't marking int zero to string zero as
28
+ # changed.
29
+ value.to_s !~ /\A-?\d+\.?\d*\z/
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ require "active_support/core_ext/time/zones"
2
+
3
+ module ActiveModel
4
+ module Type
5
+ module Helpers
6
+ module TimeValue # :nodoc:
7
+ def serialize(value)
8
+ value = apply_seconds_precision(value)
9
+
10
+ if value.acts_like?(:time)
11
+ zone_conversion_method = is_utc? ? :getutc : :getlocal
12
+
13
+ if value.respond_to?(zone_conversion_method)
14
+ value = value.send(zone_conversion_method)
15
+ end
16
+ end
17
+
18
+ value
19
+ end
20
+
21
+ def is_utc?
22
+ ::Time.zone_default.nil? || ::Time.zone_default =~ 'UTC'
23
+ end
24
+
25
+ def default_timezone
26
+ if is_utc?
27
+ :utc
28
+ else
29
+ :local
30
+ end
31
+ end
32
+
33
+ def apply_seconds_precision(value)
34
+ return value unless precision && value.respond_to?(:usec)
35
+ number_of_insignificant_digits = 6 - precision
36
+ round_power = 10 ** number_of_insignificant_digits
37
+ value.change(usec: value.usec / round_power * round_power)
38
+ end
39
+
40
+ def type_cast_for_schema(value)
41
+ "'#{value.to_s(:db)}'"
42
+ end
43
+
44
+ def user_input_in_time_zone(value)
45
+ value.in_time_zone
46
+ end
47
+
48
+ private
49
+
50
+ def new_time(year, mon, mday, hour, min, sec, microsec, offset = nil)
51
+ # Treat 0000-00-00 00:00:00 as nil.
52
+ return if year.nil? || (year == 0 && mon == 0 && mday == 0)
53
+
54
+ if offset
55
+ time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
56
+ return unless time
57
+
58
+ time -= offset
59
+ is_utc? ? time : time.getlocal
60
+ else
61
+ ::Time.public_send(default_timezone, year, mon, mday, hour, min, sec, microsec) rescue nil
62
+ end
63
+ end
64
+
65
+ ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
66
+
67
+ # Doesn't handle time zones.
68
+ def fast_string_to_time(string)
69
+ if string =~ ISO_DATETIME
70
+ microsec = ($7.to_r * 1_000_000).to_i
71
+ new_time $1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i, microsec
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,4 @@
1
+ require 'active_model/type/helpers/accepts_multiparameter_time'
2
+ require 'active_model/type/helpers/numeric'
3
+ require 'active_model/type/helpers/mutable'
4
+ require 'active_model/type/helpers/time_value'
@@ -0,0 +1,29 @@
1
+ module ActiveModel
2
+ module Type
3
+ class ImmutableString < Value # :nodoc:
4
+ def type
5
+ :string
6
+ end
7
+
8
+ def serialize(value)
9
+ case value
10
+ when ::Numeric, ActiveSupport::Duration then value.to_s
11
+ when true then "t"
12
+ when false then "f"
13
+ else super
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def cast_value(value)
20
+ result = case value
21
+ when true then "t"
22
+ when false then "f"
23
+ else value.to_s
24
+ end
25
+ result.freeze
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,66 @@
1
+ module ActiveModel
2
+ module Type
3
+ class Integer < Value # :nodoc:
4
+ include Helpers::Numeric
5
+
6
+ # Column storage size in bytes.
7
+ # 4 bytes means a MySQL int or Postgres integer as opposed to smallint etc.
8
+ DEFAULT_LIMIT = 4
9
+
10
+ def initialize(*)
11
+ super
12
+ @range = min_value...max_value
13
+ end
14
+
15
+ def type
16
+ :integer
17
+ end
18
+
19
+ def deserialize(value)
20
+ return if value.nil?
21
+ value.to_i
22
+ end
23
+
24
+ def serialize(value)
25
+ result = cast(value)
26
+ if result
27
+ ensure_in_range(result)
28
+ end
29
+ result
30
+ end
31
+
32
+ protected
33
+
34
+ attr_reader :range
35
+
36
+ private
37
+
38
+ def cast_value(value)
39
+ case value
40
+ when true then 1
41
+ when false then 0
42
+ else
43
+ value.to_i rescue nil
44
+ end
45
+ end
46
+
47
+ def ensure_in_range(value)
48
+ unless range.cover?(value)
49
+ raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit}"
50
+ end
51
+ end
52
+
53
+ def max_value
54
+ 1 << (_limit * 8 - 1) # 8 bits per byte with one bit for sign
55
+ end
56
+
57
+ def min_value
58
+ -max_value
59
+ end
60
+
61
+ def _limit
62
+ self.limit || DEFAULT_LIMIT
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,64 @@
1
+ module ActiveModel
2
+ # :stopdoc:
3
+ module Type
4
+ class Registry
5
+ def initialize
6
+ @registrations = []
7
+ end
8
+
9
+ def register(type_name, klass = nil, **options, &block)
10
+ block ||= proc { |_, *args| klass.new(*args) }
11
+ registrations << registration_klass.new(type_name, block, **options)
12
+ end
13
+
14
+ def lookup(symbol, *args)
15
+ registration = find_registration(symbol, *args)
16
+
17
+ if registration
18
+ registration.call(self, symbol, *args)
19
+ else
20
+ raise ArgumentError, "Unknown type #{symbol.inspect}"
21
+ end
22
+ end
23
+
24
+ protected
25
+
26
+ attr_reader :registrations
27
+
28
+ private
29
+
30
+ def registration_klass
31
+ Registration
32
+ end
33
+
34
+ def find_registration(symbol, *args)
35
+ registrations.find { |r| r.matches?(symbol, *args) }
36
+ end
37
+ end
38
+
39
+ class Registration
40
+ # Options must be taken because of https://bugs.ruby-lang.org/issues/10856
41
+ def initialize(name, block, **)
42
+ @name = name
43
+ @block = block
44
+ end
45
+
46
+ def call(_registry, *args, **kwargs)
47
+ if kwargs.any? # https://bugs.ruby-lang.org/issues/10856
48
+ block.call(*args, **kwargs)
49
+ else
50
+ block.call(*args)
51
+ end
52
+ end
53
+
54
+ def matches?(type_name, *args, **kwargs)
55
+ type_name == name
56
+ end
57
+
58
+ protected
59
+
60
+ attr_reader :name, :block
61
+ end
62
+ end
63
+ # :startdoc:
64
+ end
@@ -0,0 +1,24 @@
1
+ require "active_model/type/immutable_string"
2
+
3
+ module ActiveModel
4
+ module Type
5
+ class String < ImmutableString # :nodoc:
6
+ def changed_in_place?(raw_old_value, new_value)
7
+ if new_value.is_a?(::String)
8
+ raw_old_value != new_value
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def cast_value(value)
15
+ case value
16
+ when ::String then ::String.new(value)
17
+ when true then "t".freeze
18
+ when false then "f".freeze
19
+ else value.to_s
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,11 @@
1
+ require 'active_model/type/string'
2
+
3
+ module ActiveModel
4
+ module Type
5
+ class Text < String # :nodoc:
6
+ def type
7
+ :text
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,42 @@
1
+ module ActiveModel
2
+ module Type
3
+ class Time < Value # :nodoc:
4
+ include Helpers::TimeValue
5
+ include Helpers::AcceptsMultiparameterTime.new(
6
+ defaults: { 1 => 1970, 2 => 1, 3 => 1, 4 => 0, 5 => 0 }
7
+ )
8
+
9
+ def type
10
+ :time
11
+ end
12
+
13
+ def user_input_in_time_zone(value)
14
+ return unless value.present?
15
+
16
+ case value
17
+ when ::String
18
+ value = "2000-01-01 #{value}"
19
+ when ::Time
20
+ value = value.change(year: 2000, day: 1, month: 1)
21
+ end
22
+
23
+ super(value)
24
+ end
25
+
26
+ private
27
+
28
+ def cast_value(value)
29
+ return apply_seconds_precision(value) unless value.is_a?(::String)
30
+ return if value.empty?
31
+
32
+ dummy_time_value = value.sub(/\A(\d\d\d\d-\d\d-\d\d |)/, "2000-01-01 ")
33
+
34
+ fast_string_to_time(dummy_time_value) || begin
35
+ time_hash = ::Date._parse(dummy_time_value)
36
+ return if time_hash[:hour].nil?
37
+ new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,15 @@
1
+ module ActiveModel
2
+ module Type
3
+ class UnsignedInteger < Integer # :nodoc:
4
+ private
5
+
6
+ def max_value
7
+ super * 2
8
+ end
9
+
10
+ def min_value
11
+ 0
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,116 @@
1
+ module ActiveModel
2
+ module Type
3
+ class Value
4
+ attr_reader :precision, :scale, :limit
5
+
6
+ def initialize(precision: nil, limit: nil, scale: nil)
7
+ @precision = precision
8
+ @scale = scale
9
+ @limit = limit
10
+ end
11
+
12
+ def type # :nodoc:
13
+ end
14
+
15
+ # Converts a value from database input to the appropriate ruby type. The
16
+ # return value of this method will be returned from
17
+ # ActiveRecord::AttributeMethods::Read#read_attribute. The default
18
+ # implementation just calls Value#cast.
19
+ #
20
+ # +value+ The raw input, as provided from the database.
21
+ def deserialize(value)
22
+ cast(value)
23
+ end
24
+
25
+ # Type casts a value from user input (e.g. from a setter). This value may
26
+ # be a string from the form builder, or a ruby object passed to a setter.
27
+ # There is currently no way to differentiate between which source it came
28
+ # from.
29
+ #
30
+ # The return value of this method will be returned from
31
+ # ActiveRecord::AttributeMethods::Read#read_attribute. See also:
32
+ # Value#cast_value.
33
+ #
34
+ # +value+ The raw input, as provided to the attribute setter.
35
+ def cast(value)
36
+ cast_value(value) unless value.nil?
37
+ end
38
+
39
+ # Casts a value from the ruby type to a type that the database knows how
40
+ # to understand. The returned value from this method should be a
41
+ # +String+, +Numeric+, +Date+, +Time+, +Symbol+, +true+, +false+, or
42
+ # +nil+.
43
+ def serialize(value)
44
+ value
45
+ end
46
+
47
+ # Type casts a value for schema dumping. This method is private, as we are
48
+ # hoping to remove it entirely.
49
+ def type_cast_for_schema(value) # :nodoc:
50
+ value.inspect
51
+ end
52
+
53
+ # These predicates are not documented, as I need to look further into
54
+ # their use, and see if they can be removed entirely.
55
+ def binary? # :nodoc:
56
+ false
57
+ end
58
+
59
+ # Determines whether a value has changed for dirty checking. +old_value+
60
+ # and +new_value+ will always be type-cast. Types should not need to
61
+ # override this method.
62
+ def changed?(old_value, new_value, _new_value_before_type_cast)
63
+ old_value != new_value
64
+ end
65
+
66
+ # Determines whether the mutable value has been modified since it was
67
+ # read. Returns +false+ by default. If your type returns an object
68
+ # which could be mutated, you should override this method. You will need
69
+ # to either:
70
+ #
71
+ # - pass +new_value+ to Value#serialize and compare it to
72
+ # +raw_old_value+
73
+ #
74
+ # or
75
+ #
76
+ # - pass +raw_old_value+ to Value#deserialize and compare it to
77
+ # +new_value+
78
+ #
79
+ # +raw_old_value+ The original value, before being passed to
80
+ # +deserialize+.
81
+ #
82
+ # +new_value+ The current value, after type casting.
83
+ def changed_in_place?(raw_old_value, new_value)
84
+ false
85
+ end
86
+
87
+ def map(value) # :nodoc:
88
+ yield value
89
+ end
90
+
91
+ def ==(other)
92
+ self.class == other.class &&
93
+ precision == other.precision &&
94
+ scale == other.scale &&
95
+ limit == other.limit
96
+ end
97
+ alias eql? ==
98
+
99
+ def hash
100
+ [self.class, precision, scale, limit].hash
101
+ end
102
+
103
+ def assert_valid_value(*)
104
+ end
105
+
106
+ private
107
+
108
+ # Convenience method for types which do not need separate type casting
109
+ # behavior for user and database inputs. Called by Value#cast for
110
+ # values except +nil+.
111
+ def cast_value(value) # :doc:
112
+ value
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,59 @@
1
+ require 'active_model/type/helpers'
2
+ require 'active_model/type/value'
3
+
4
+ require 'active_model/type/big_integer'
5
+ require 'active_model/type/binary'
6
+ require 'active_model/type/boolean'
7
+ require 'active_model/type/date'
8
+ require 'active_model/type/date_time'
9
+ require 'active_model/type/decimal'
10
+ require 'active_model/type/decimal_without_scale'
11
+ require 'active_model/type/float'
12
+ require 'active_model/type/immutable_string'
13
+ require 'active_model/type/integer'
14
+ require 'active_model/type/string'
15
+ require 'active_model/type/text'
16
+ require 'active_model/type/time'
17
+ require 'active_model/type/unsigned_integer'
18
+
19
+ require 'active_model/type/registry'
20
+
21
+ module ActiveModel
22
+ module Type
23
+ @registry = Registry.new
24
+
25
+ class << self
26
+ attr_accessor :registry # :nodoc:
27
+ delegate :add_modifier, to: :registry
28
+
29
+ # Add a new type to the registry, allowing it to be referenced as a
30
+ # symbol by ActiveModel::Attributes::ClassMethods#attribute. If your
31
+ # type is only meant to be used with a specific database adapter, you can
32
+ # do so by passing +adapter: :postgresql+. If your type has the same
33
+ # name as a native type for the current adapter, an exception will be
34
+ # raised unless you specify an +:override+ option. +override: true+ will
35
+ # cause your type to be used instead of the native type. +override:
36
+ # false+ will cause the native type to be used over yours if one exists.
37
+ def register(type_name, klass = nil, **options, &block)
38
+ registry.register(type_name, klass, **options, &block)
39
+ end
40
+
41
+ def lookup(*args, **kwargs) # :nodoc:
42
+ registry.lookup(*args, **kwargs)
43
+ end
44
+ end
45
+
46
+ register(:big_integer, Type::BigInteger)
47
+ register(:binary, Type::Binary)
48
+ register(:boolean, Type::Boolean)
49
+ register(:date, Type::Date)
50
+ register(:datetime, Type::DateTime)
51
+ register(:decimal, Type::Decimal)
52
+ register(:float, Type::Float)
53
+ register(:immutable_string, Type::ImmutableString)
54
+ register(:integer, Type::Integer)
55
+ register(:string, Type::String)
56
+ register(:text, Type::Text)
57
+ register(:time, Type::Time)
58
+ end
59
+ end
@@ -1,6 +1,6 @@
1
1
  module ActiveModel
2
2
  module Validations
3
- # == Active Model Absence Validator
3
+ # == \Active \Model Absence Validator
4
4
  class AbsenceValidator < EachValidator #:nodoc:
5
5
  def validate_each(record, attr_name, value)
6
6
  record.errors.add(attr_name, :present, options) if value.present?
@@ -3,22 +3,69 @@ module ActiveModel
3
3
  module Validations
4
4
  class AcceptanceValidator < EachValidator # :nodoc:
5
5
  def initialize(options)
6
- super({ allow_nil: true, accept: "1" }.merge!(options))
6
+ super({ allow_nil: true, accept: ["1", true] }.merge!(options))
7
7
  setup!(options[:class])
8
8
  end
9
9
 
10
10
  def validate_each(record, attribute, value)
11
- unless value == options[:accept]
11
+ unless acceptable_option?(value)
12
12
  record.errors.add(attribute, :accepted, options.except(:accept, :allow_nil))
13
13
  end
14
14
  end
15
15
 
16
16
  private
17
+
17
18
  def setup!(klass)
18
- attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
19
- attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
20
- klass.send(:attr_reader, *attr_readers)
21
- klass.send(:attr_writer, *attr_writers)
19
+ klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes)))
20
+ end
21
+
22
+ def acceptable_option?(value)
23
+ Array(options[:accept]).include?(value)
24
+ end
25
+
26
+ class LazilyDefineAttributes < Module
27
+ def initialize(attribute_definition)
28
+ define_method(:respond_to_missing?) do |method_name, include_private=false|
29
+ super(method_name, include_private) || attribute_definition.matches?(method_name)
30
+ end
31
+
32
+ define_method(:method_missing) do |method_name, *args, &block|
33
+ if attribute_definition.matches?(method_name)
34
+ attribute_definition.define_on(self.class)
35
+ send(method_name, *args, &block)
36
+ else
37
+ super(method_name, *args, &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ class AttributeDefinition
44
+ def initialize(attributes)
45
+ @attributes = attributes.map(&:to_s)
46
+ end
47
+
48
+ def matches?(method_name)
49
+ attr_name = convert_to_reader_name(method_name)
50
+ attributes.include?(attr_name)
51
+ end
52
+
53
+ def define_on(klass)
54
+ attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
55
+ attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
56
+ klass.send(:attr_reader, *attr_readers)
57
+ klass.send(:attr_writer, *attr_writers)
58
+ end
59
+
60
+ protected
61
+
62
+ attr_reader :attributes
63
+
64
+ private
65
+
66
+ def convert_to_reader_name(method_name)
67
+ method_name.to_s.chomp('=')
68
+ end
22
69
  end
23
70
  end
24
71
 
@@ -38,9 +85,10 @@ module ActiveModel
38
85
  # Configuration options:
39
86
  # * <tt>:message</tt> - A custom error message (default is: "must be
40
87
  # accepted").
41
- # * <tt>:accept</tt> - Specifies value that is considered accepted.
42
- # The default value is a string "1", which makes it easy to relate to
43
- # an HTML checkbox. This should be set to +true+ if you are validating
88
+ # * <tt>:accept</tt> - Specifies a value that is considered accepted.
89
+ # Also accepts an array of possible values. The default value is
90
+ # an array ["1", true], which makes it easy to relate to an HTML
91
+ # checkbox. This should be set to, or include, +true+ if you are validating
44
92
  # a database column, since the attribute is typecast from "1" to +true+
45
93
  # before validation.
46
94
  #
@@ -15,15 +15,15 @@ module ActiveModel
15
15
  # after_validation :do_stuff_after_validation
16
16
  # end
17
17
  #
18
- # Like other <tt>before_*</tt> callbacks if +before_validation+ returns
19
- # +false+ then <tt>valid?</tt> will not be called.
18
+ # Like other <tt>before_*</tt> callbacks if +before_validation+ throws
19
+ # +:abort+ then <tt>valid?</tt> will not be called.
20
20
  module Callbacks
21
21
  extend ActiveSupport::Concern
22
22
 
23
23
  included do
24
24
  include ActiveSupport::Callbacks
25
25
  define_callbacks :validation,
26
- terminator: ->(_,result) { result == false },
26
+ terminator: deprecated_false_terminator,
27
27
  skip_after_callbacks_if_terminated: true,
28
28
  scope: [:kind, :name]
29
29
  end