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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +15 -219
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/active_model.rb +11 -12
- data/lib/active_model/attribute_assignment.rb +11 -11
- data/lib/active_model/attribute_methods.rb +13 -15
- data/lib/active_model/callbacks.rb +19 -20
- data/lib/active_model/conversion.rb +12 -3
- data/lib/active_model/dirty.rb +14 -14
- data/lib/active_model/errors.rb +27 -103
- data/lib/active_model/forbidden_attributes_protection.rb +1 -1
- data/lib/active_model/gem_version.rb +3 -3
- data/lib/active_model/lint.rb +0 -1
- data/lib/active_model/model.rb +3 -4
- data/lib/active_model/naming.rb +9 -10
- data/lib/active_model/secure_password.rb +1 -1
- data/lib/active_model/serialization.rb +2 -2
- data/lib/active_model/serializers/json.rb +2 -2
- data/lib/active_model/translation.rb +2 -3
- data/lib/active_model/type.rb +15 -19
- data/lib/active_model/type/big_integer.rb +4 -4
- data/lib/active_model/type/binary.rb +1 -1
- data/lib/active_model/type/boolean.rb +20 -9
- data/lib/active_model/type/date.rb +25 -25
- data/lib/active_model/type/date_time.rb +21 -21
- data/lib/active_model/type/decimal.rb +35 -39
- data/lib/active_model/type/float.rb +17 -8
- data/lib/active_model/type/helpers.rb +4 -4
- data/lib/active_model/type/helpers/accepts_multiparameter_time.rb +2 -2
- data/lib/active_model/type/helpers/mutable.rb +2 -2
- data/lib/active_model/type/helpers/numeric.rb +18 -17
- data/lib/active_model/type/helpers/time_value.rb +23 -23
- data/lib/active_model/type/immutable_string.rb +9 -8
- data/lib/active_model/type/integer.rb +23 -21
- data/lib/active_model/type/registry.rb +12 -8
- data/lib/active_model/type/string.rb +1 -6
- data/lib/active_model/type/time.rb +15 -11
- data/lib/active_model/type/value.rb +6 -6
- data/lib/active_model/validations.rb +9 -12
- data/lib/active_model/validations/absence.rb +1 -1
- data/lib/active_model/validations/acceptance.rb +41 -40
- data/lib/active_model/validations/callbacks.rb +4 -7
- data/lib/active_model/validations/clusivity.rb +7 -7
- data/lib/active_model/validations/confirmation.rb +15 -16
- data/lib/active_model/validations/exclusion.rb +1 -2
- data/lib/active_model/validations/format.rb +24 -24
- data/lib/active_model/validations/inclusion.rb +1 -2
- data/lib/active_model/validations/length.rb +6 -42
- data/lib/active_model/validations/numericality.rb +3 -11
- data/lib/active_model/validations/presence.rb +1 -2
- data/lib/active_model/validations/validates.rb +6 -6
- data/lib/active_model/validations/with.rb +4 -2
- data/lib/active_model/validator.rb +5 -6
- data/lib/active_model/version.rb +1 -1
- metadata +8 -11
- data/lib/active_model/test_case.rb +0 -4
- data/lib/active_model/type/decimal_without_scale.rb +0 -11
- data/lib/active_model/type/text.rb +0 -11
- data/lib/active_model/type/unsigned_integer.rb +0 -15
@@ -1,14 +1,15 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
module Type
|
3
|
-
module Helpers
|
4
|
-
module Numeric
|
3
|
+
module Helpers # :nodoc: all
|
4
|
+
module Numeric
|
5
5
|
def cast(value)
|
6
|
-
value =
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
6
|
+
value = \
|
7
|
+
case value
|
8
|
+
when true then 1
|
9
|
+
when false then 0
|
10
|
+
when ::String then value.presence
|
11
|
+
else value
|
12
|
+
end
|
12
13
|
super(value)
|
13
14
|
end
|
14
15
|
|
@@ -18,16 +19,16 @@ module ActiveModel
|
|
18
19
|
|
19
20
|
private
|
20
21
|
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
def number_to_non_number?(old_value, new_value_before_type_cast)
|
23
|
+
old_value != nil && non_numeric_string?(new_value_before_type_cast)
|
24
|
+
end
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
26
|
+
def non_numeric_string?(value)
|
27
|
+
# 'wibble'.to_i will give zero, we want to make sure
|
28
|
+
# that we aren't marking int zero to string zero as
|
29
|
+
# changed.
|
30
|
+
value.to_s !~ /\A-?\d+\.?\d*\z/
|
31
|
+
end
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
@@ -2,8 +2,8 @@ require "active_support/core_ext/time/zones"
|
|
2
2
|
|
3
3
|
module ActiveModel
|
4
4
|
module Type
|
5
|
-
module Helpers
|
6
|
-
module TimeValue
|
5
|
+
module Helpers # :nodoc: all
|
6
|
+
module TimeValue
|
7
7
|
def serialize(value)
|
8
8
|
value = apply_seconds_precision(value)
|
9
9
|
|
@@ -19,7 +19,7 @@ module ActiveModel
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def is_utc?
|
22
|
-
::Time.zone_default.nil? || ::Time.zone_default =~
|
22
|
+
::Time.zone_default.nil? || ::Time.zone_default =~ "UTC"
|
23
23
|
end
|
24
24
|
|
25
25
|
def default_timezone
|
@@ -33,8 +33,8 @@ module ActiveModel
|
|
33
33
|
def apply_seconds_precision(value)
|
34
34
|
return value unless precision && value.respond_to?(:usec)
|
35
35
|
number_of_insignificant_digits = 6 - precision
|
36
|
-
round_power = 10
|
37
|
-
value.change(usec: value.usec
|
36
|
+
round_power = 10**number_of_insignificant_digits
|
37
|
+
value.change(usec: value.usec - value.usec % round_power)
|
38
38
|
end
|
39
39
|
|
40
40
|
def type_cast_for_schema(value)
|
@@ -47,30 +47,30 @@ module ActiveModel
|
|
47
47
|
|
48
48
|
private
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
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
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
if offset
|
55
|
+
time = ::Time.utc(year, mon, mday, hour, min, sec, microsec) rescue nil
|
56
|
+
return unless time
|
57
57
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
62
63
|
end
|
63
|
-
end
|
64
64
|
|
65
|
-
|
65
|
+
ISO_DATETIME = /\A(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)(\.\d+)?\z/
|
66
66
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
72
73
|
end
|
73
|
-
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
end
|
@@ -16,14 +16,15 @@ module ActiveModel
|
|
16
16
|
|
17
17
|
private
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
def cast_value(value)
|
20
|
+
result = \
|
21
|
+
case value
|
22
|
+
when true then "t"
|
23
|
+
when false then "f"
|
24
|
+
else value.to_s
|
25
|
+
end
|
26
|
+
result.freeze
|
27
|
+
end
|
27
28
|
end
|
28
29
|
end
|
29
30
|
end
|
@@ -29,38 +29,40 @@ module ActiveModel
|
|
29
29
|
result
|
30
30
|
end
|
31
31
|
|
32
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
33
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
32
34
|
protected
|
33
35
|
|
34
|
-
|
36
|
+
attr_reader :range
|
35
37
|
|
36
38
|
private
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
def cast_value(value)
|
41
|
+
case value
|
42
|
+
when true then 1
|
43
|
+
when false then 0
|
44
|
+
else
|
45
|
+
value.to_i rescue nil
|
46
|
+
end
|
44
47
|
end
|
45
|
-
end
|
46
48
|
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
def ensure_in_range(value)
|
50
|
+
unless range.cover?(value)
|
51
|
+
raise ActiveModel::RangeError, "#{value} is out of range for #{self.class} with limit #{_limit} bytes"
|
52
|
+
end
|
50
53
|
end
|
51
|
-
end
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
55
|
+
def max_value
|
56
|
+
1 << (_limit * 8 - 1) # 8 bits per byte with one bit for sign
|
57
|
+
end
|
56
58
|
|
57
|
-
|
58
|
-
|
59
|
-
|
59
|
+
def min_value
|
60
|
+
-max_value
|
61
|
+
end
|
60
62
|
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
def _limit
|
64
|
+
limit || DEFAULT_LIMIT
|
65
|
+
end
|
64
66
|
end
|
65
67
|
end
|
66
68
|
end
|
@@ -21,19 +21,21 @@ module ActiveModel
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
|
24
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
25
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
24
26
|
protected
|
25
27
|
|
26
|
-
|
28
|
+
attr_reader :registrations
|
27
29
|
|
28
30
|
private
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
32
|
+
def registration_klass
|
33
|
+
Registration
|
34
|
+
end
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
def find_registration(symbol, *args)
|
37
|
+
registrations.find { |r| r.matches?(symbol, *args) }
|
38
|
+
end
|
37
39
|
end
|
38
40
|
|
39
41
|
class Registration
|
@@ -55,9 +57,11 @@ module ActiveModel
|
|
55
57
|
type_name == name
|
56
58
|
end
|
57
59
|
|
60
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
61
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
58
62
|
protected
|
59
63
|
|
60
|
-
|
64
|
+
attr_reader :name, :block
|
61
65
|
end
|
62
66
|
end
|
63
67
|
# :startdoc:
|
@@ -25,18 +25,22 @@ module ActiveModel
|
|
25
25
|
|
26
26
|
private
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
28
|
+
def cast_value(value)
|
29
|
+
return value unless value.is_a?(::String)
|
30
|
+
return if value.empty?
|
31
|
+
|
32
|
+
if value.start_with?("2000-01-01")
|
33
|
+
dummy_time_value = value
|
34
|
+
else
|
35
|
+
dummy_time_value = "2000-01-01 #{value}"
|
36
|
+
end
|
37
|
+
|
38
|
+
fast_string_to_time(dummy_time_value) || begin
|
39
|
+
time_hash = ::Date._parse(dummy_time_value)
|
40
|
+
return if time_hash[:hour].nil?
|
41
|
+
new_time(*time_hash.values_at(:year, :mon, :mday, :hour, :min, :sec, :sec_fraction, :offset))
|
42
|
+
end
|
38
43
|
end
|
39
|
-
end
|
40
44
|
end
|
41
45
|
end
|
42
46
|
end
|
@@ -105,12 +105,12 @@ module ActiveModel
|
|
105
105
|
|
106
106
|
private
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
114
|
end
|
115
115
|
end
|
116
116
|
end
|
@@ -1,9 +1,8 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/core_ext/array/extract_options"
|
2
|
+
require "active_support/core_ext/hash/keys"
|
3
|
+
require "active_support/core_ext/hash/except"
|
4
4
|
|
5
5
|
module ActiveModel
|
6
|
-
|
7
6
|
# == Active \Model \Validations
|
8
7
|
#
|
9
8
|
# Provides a full validation framework to your objects.
|
@@ -51,7 +50,7 @@ module ActiveModel
|
|
51
50
|
define_callbacks :validate, scope: :name
|
52
51
|
|
53
52
|
class_attribute :_validators, instance_writer: false
|
54
|
-
self._validators = Hash.new { |h,k| h[k] = [] }
|
53
|
+
self._validators = Hash.new { |h, k| h[k] = [] }
|
55
54
|
end
|
56
55
|
|
57
56
|
module ClassMethods
|
@@ -69,7 +68,7 @@ module ActiveModel
|
|
69
68
|
#
|
70
69
|
# Options:
|
71
70
|
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
72
|
-
# Runs in all validation contexts by default
|
71
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
73
72
|
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
74
73
|
# <tt>on: :custom_validation_context</tt> or
|
75
74
|
# <tt>on: [:create, :custom_validation_context]</tt>)
|
@@ -135,7 +134,7 @@ module ActiveModel
|
|
135
134
|
#
|
136
135
|
# Options:
|
137
136
|
# * <tt>:on</tt> - Specifies the contexts where this validation is active.
|
138
|
-
# Runs in all validation contexts by default
|
137
|
+
# Runs in all validation contexts by default +nil+. You can pass a symbol
|
139
138
|
# or an array of symbols. (e.g. <tt>on: :create</tt> or
|
140
139
|
# <tt>on: :custom_validation_context</tt> or
|
141
140
|
# <tt>on: [:create, :custom_validation_context]</tt>)
|
@@ -304,8 +303,6 @@ module ActiveModel
|
|
304
303
|
# Runs all the specified validations and returns +true+ if no errors were
|
305
304
|
# added otherwise +false+.
|
306
305
|
#
|
307
|
-
# Aliased as validate.
|
308
|
-
#
|
309
306
|
# class Person
|
310
307
|
# include ActiveModel::Validations
|
311
308
|
#
|
@@ -402,14 +399,14 @@ module ActiveModel
|
|
402
399
|
# end
|
403
400
|
alias :read_attribute_for_validation :send
|
404
401
|
|
405
|
-
|
402
|
+
private
|
406
403
|
|
407
|
-
def run_validations!
|
404
|
+
def run_validations!
|
408
405
|
_run_validate_callbacks
|
409
406
|
errors.empty?
|
410
407
|
end
|
411
408
|
|
412
|
-
def raise_validation_error
|
409
|
+
def raise_validation_error # :doc:
|
413
410
|
raise(ValidationError.new(self))
|
414
411
|
end
|
415
412
|
end
|
@@ -22,7 +22,7 @@ module ActiveModel
|
|
22
22
|
#
|
23
23
|
# There is also a list of default options supported by every validator:
|
24
24
|
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
25
|
-
# See <tt>ActiveModel::
|
25
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information
|
26
26
|
def validates_absence_of(*attr_names)
|
27
27
|
validates_with AbsenceValidator, _merge_attributes(attr_names)
|
28
28
|
end
|
@@ -1,5 +1,4 @@
|
|
1
1
|
module ActiveModel
|
2
|
-
|
3
2
|
module Validations
|
4
3
|
class AcceptanceValidator < EachValidator # :nodoc:
|
5
4
|
def initialize(options)
|
@@ -15,58 +14,60 @@ module ActiveModel
|
|
15
14
|
|
16
15
|
private
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
def setup!(klass)
|
18
|
+
klass.include(LazilyDefineAttributes.new(AttributeDefinition.new(attributes)))
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
def acceptable_option?(value)
|
22
|
+
Array(options[:accept]).include?(value)
|
23
|
+
end
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
25
|
+
class LazilyDefineAttributes < Module
|
26
|
+
def initialize(attribute_definition)
|
27
|
+
define_method(:respond_to_missing?) do |method_name, include_private = false|
|
28
|
+
super(method_name, include_private) || attribute_definition.matches?(method_name)
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
31
|
+
define_method(:method_missing) do |method_name, *args, &block|
|
32
|
+
if attribute_definition.matches?(method_name)
|
33
|
+
attribute_definition.define_on(self.class)
|
34
|
+
send(method_name, *args, &block)
|
35
|
+
else
|
36
|
+
super(method_name, *args, &block)
|
37
|
+
end
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
|
-
end
|
42
41
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
class AttributeDefinition
|
43
|
+
def initialize(attributes)
|
44
|
+
@attributes = attributes.map(&:to_s)
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
def matches?(method_name)
|
48
|
+
attr_name = convert_to_reader_name(method_name)
|
49
|
+
attributes.include?(attr_name)
|
50
|
+
end
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
52
|
+
def define_on(klass)
|
53
|
+
attr_readers = attributes.reject { |name| klass.attribute_method?(name) }
|
54
|
+
attr_writers = attributes.reject { |name| klass.attribute_method?("#{name}=") }
|
55
|
+
klass.send(:attr_reader, *attr_readers)
|
56
|
+
klass.send(:attr_writer, *attr_writers)
|
57
|
+
end
|
59
58
|
|
60
|
-
|
59
|
+
# TODO Change this to private once we've dropped Ruby 2.2 support.
|
60
|
+
# Workaround for Ruby 2.2 "private attribute?" warning.
|
61
|
+
protected
|
61
62
|
|
62
|
-
|
63
|
+
attr_reader :attributes
|
63
64
|
|
64
|
-
|
65
|
+
private
|
65
66
|
|
66
|
-
|
67
|
-
|
67
|
+
def convert_to_reader_name(method_name)
|
68
|
+
method_name.to_s.chomp("=")
|
69
|
+
end
|
68
70
|
end
|
69
|
-
end
|
70
71
|
end
|
71
72
|
|
72
73
|
module HelperMethods
|
@@ -94,7 +95,7 @@ module ActiveModel
|
|
94
95
|
#
|
95
96
|
# There is also a list of default options supported by every validator:
|
96
97
|
# +:if+, +:unless+, +:on+, +:allow_nil+, +:allow_blank+, and +:strict+.
|
97
|
-
# See <tt>ActiveModel::
|
98
|
+
# See <tt>ActiveModel::Validations#validates</tt> for more information.
|
98
99
|
def validates_acceptance_of(*attr_names)
|
99
100
|
validates_with AcceptanceValidator, _merge_attributes(attr_names)
|
100
101
|
end
|