1
0
Fork 0
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:
Ryuta Kamizono 2021-03-15 12:23:40 +09:00
parent 520bb79411
commit c435af140e
5 changed files with 48 additions and 7 deletions

View file

@ -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?

View file

@ -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

View file

@ -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)

View file

@ -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

View file

@ -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?