mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Don't use type.cast(value)
to emulate unchecked serialized value in unboundable?
I used `type.cast(value)` to emulate unchecked serialized value in
`unboundable?`, since `RangeError` was raised only for the integer type,
so the emulation works enough for the integer type.
But since #41516, Enum types are also not always serializable, so
`type.cast(value)` may also be called for the enum types.
I've delegated `type.cast(value)` to the subtype if an unknown label is
passed to work the emulation even on Enum types in 3b6461b
. But it is
strange to delegate to the subtype for the emulation only if an unknown
label is passed.
Instead of using `type.cast(value)` for the emulation, extend
`serializable?` to get unchecked serialized value if the value is not
serializable.
This commit is contained in:
parent
520bb79411
commit
c435af140e
5 changed files with 48 additions and 7 deletions
|
@ -56,8 +56,8 @@ module ActiveModel
|
|||
type.serialize(value)
|
||||
end
|
||||
|
||||
def serializable?
|
||||
type.serializable?(value)
|
||||
def serializable?(&block)
|
||||
type.serializable?(value, &block)
|
||||
end
|
||||
|
||||
def changed?
|
||||
|
|
|
@ -30,7 +30,10 @@ module ActiveModel
|
|||
|
||||
def serializable?(value)
|
||||
cast_value = cast(value)
|
||||
in_range?(cast_value) && super
|
||||
in_range?(cast_value) || begin
|
||||
yield cast_value if block_given?
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -129,7 +129,7 @@ module ActiveRecord
|
|||
elsif mapping.has_value?(value)
|
||||
mapping.key(value)
|
||||
else
|
||||
subtype.cast(value.presence)
|
||||
value.presence
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -141,8 +141,8 @@ module ActiveRecord
|
|||
subtype.serialize(mapping.fetch(value, value))
|
||||
end
|
||||
|
||||
def serializable?(value)
|
||||
subtype.serializable?(mapping.fetch(value, value))
|
||||
def serializable?(value, &block)
|
||||
subtype.serializable?(mapping.fetch(value, value), &block)
|
||||
end
|
||||
|
||||
def assert_valid_value(value)
|
||||
|
|
|
@ -30,7 +30,7 @@ module ActiveRecord
|
|||
|
||||
def unboundable?
|
||||
unless defined?(@_unboundable)
|
||||
@_unboundable = !serializable? && type.cast(value) <=> 0
|
||||
serializable? { |value| @_unboundable = value <=> 0 } && @_unboundable = nil
|
||||
end
|
||||
@_unboundable
|
||||
end
|
||||
|
|
|
@ -12,6 +12,44 @@ class EnumTest < ActiveRecord::TestCase
|
|||
@book = books(:awdr)
|
||||
end
|
||||
|
||||
test "type.cast" do
|
||||
type = Book.type_for_attribute(:status)
|
||||
|
||||
assert_equal "proposed", type.cast(0)
|
||||
assert_equal "written", type.cast(1)
|
||||
assert_equal "published", type.cast(2)
|
||||
|
||||
assert_equal "proposed", type.cast(:proposed)
|
||||
assert_equal "written", type.cast(:written)
|
||||
assert_equal "published", type.cast(:published)
|
||||
|
||||
assert_equal "proposed", type.cast("proposed")
|
||||
assert_equal "written", type.cast("written")
|
||||
assert_equal "published", type.cast("published")
|
||||
|
||||
assert_equal :unknown, type.cast(:unknown)
|
||||
assert_equal "unknown", type.cast("unknown")
|
||||
end
|
||||
|
||||
test "type.serialize" do
|
||||
type = Book.type_for_attribute(:status)
|
||||
|
||||
assert_equal 0, type.serialize(0)
|
||||
assert_equal 1, type.serialize(1)
|
||||
assert_equal 2, type.serialize(2)
|
||||
|
||||
assert_equal 0, type.serialize(:proposed)
|
||||
assert_equal 1, type.serialize(:written)
|
||||
assert_equal 2, type.serialize(:published)
|
||||
|
||||
assert_equal 0, type.serialize("proposed")
|
||||
assert_equal 1, type.serialize("written")
|
||||
assert_equal 2, type.serialize("published")
|
||||
|
||||
assert_nil type.serialize(:unknown)
|
||||
assert_nil type.serialize("unknown")
|
||||
end
|
||||
|
||||
test "query state by predicate" do
|
||||
assert_predicate @book, :published?
|
||||
assert_not_predicate @book, :written?
|
||||
|
|
Loading…
Reference in a new issue