1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Revert "Merge pull request #39929 from jonathanhefner/decorate-original-attribute-type"

This reverts commit 79d0c17c65, reversing
changes made to bc828f74df.

Fixes #41138.
This commit is contained in:
Ryuta Kamizono 2021-01-16 14:44:39 +09:00
parent b5ab89b9bf
commit 5fc0c4c562
4 changed files with 35 additions and 42 deletions

View file

@ -128,7 +128,7 @@ module ActiveRecord
Coders::YAMLColumn.new(attr_name, class_name_or_coder) Coders::YAMLColumn.new(attr_name, class_name_or_coder)
end end
attribute(attr_name, **options) do |cast_type| decorate_attribute_type(attr_name.to_s, **options) do |cast_type|
if type_incompatible_with_serialize?(cast_type, class_name_or_coder) if type_incompatible_with_serialize?(cast_type, class_name_or_coder)
raise ColumnNotSerializableError.new(attr_name, cast_type) raise ColumnNotSerializableError.new(attr_name, cast_type)
end end

View file

@ -208,21 +208,14 @@ module ActiveRecord
# tracking is performed. The methods +changed?+ and +changed_in_place?+ # tracking is performed. The methods +changed?+ and +changed_in_place?+
# will be called from ActiveModel::Dirty. See the documentation for those # will be called from ActiveModel::Dirty. See the documentation for those
# methods in ActiveModel::Type::Value for more details. # methods in ActiveModel::Type::Value for more details.
def attribute(name, cast_type = nil, **options, &decorator) def attribute(name, cast_type = nil, **options, &block)
name = name.to_s name = name.to_s
reload_schema_from_cache reload_schema_from_cache
prev_cast_type, prev_options, prev_decorator = attributes_to_define_after_schema_loads[name] self.attributes_to_define_after_schema_loads =
attributes_to_define_after_schema_loads.merge(
unless cast_type && prev_cast_type name => [cast_type || block, options]
cast_type ||= prev_cast_type )
options = prev_options || options if options.empty?
decorator ||= prev_decorator
end
self.attributes_to_define_after_schema_loads = attributes_to_define_after_schema_loads.merge(
name => [cast_type, options, decorator]
)
end end
# This is the low level API which sits beneath +attribute+. It only # This is the low level API which sits beneath +attribute+. It only
@ -255,16 +248,8 @@ module ActiveRecord
def load_schema! # :nodoc: def load_schema! # :nodoc:
super super
attributes_to_define_after_schema_loads.each do |name, (type, options, decorator)| attributes_to_define_after_schema_loads.each do |name, (type, options)|
if type.is_a?(Symbol) define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
type = ActiveRecord::Type.lookup(type, **options.except(:default), adapter: ActiveRecord::Type.adapter_name_from(self))
elsif type.nil?
type = type_for_attribute(name)
end
type = decorator[type] if decorator
define_attribute(name, type, **options.slice(:default))
end end
end end
@ -287,6 +272,32 @@ module ActiveRecord
end end
_default_attributes[name] = default_attribute _default_attributes[name] = default_attribute
end end
def decorate_attribute_type(attr_name, **default)
type, options = attributes_to_define_after_schema_loads[attr_name]
default.with_defaults!(default: options[:default]) if options&.key?(:default)
attribute(attr_name, **default) do |cast_type|
if type && !type.is_a?(Proc)
cast_type = _lookup_cast_type(attr_name, type, options)
end
yield cast_type
end
end
def _lookup_cast_type(name, type, options)
case type
when Symbol
adapter_name = ActiveRecord::Type.adapter_name_from(self)
ActiveRecord::Type.lookup(type, **options.except(:default), adapter: adapter_name)
when Proc
type[type_for_attribute(name)]
else
type || type_for_attribute(name)
end
end
end end
end end
end end

View file

@ -181,7 +181,7 @@ module ActiveRecord
attr = attribute_alias?(name) ? attribute_alias(name) : name attr = attribute_alias?(name) ? attribute_alias(name) : name
attribute(attr, **default) do |subtype| decorate_attribute_type(attr, **default) do |subtype|
EnumType.new(attr, enum_values, subtype) EnumType.new(attr, enum_values, subtype)
end end

View file

@ -68,15 +68,6 @@ module ActiveRecord
assert_equal "the overloaded default", klass.new.overloaded_string_with_limit assert_equal "the overloaded default", klass.new.overloaded_string_with_limit
end end
test "attributes with overridden types keep their type when a default value is configured separately" do
child = Class.new(OverloadedType) do
attribute :overloaded_float, default: "123"
end
assert_equal OverloadedType.type_for_attribute("overloaded_float"), child.type_for_attribute("overloaded_float")
assert_equal 123, child.new.overloaded_float
end
test "extra options are forwarded to the type caster constructor" do test "extra options are forwarded to the type caster constructor" do
klass = Class.new(OverloadedType) do klass = Class.new(OverloadedType) do
attribute :starts_at, :datetime, precision: 3, limit: 2, scale: 1, default: -> { Time.now.utc } attribute :starts_at, :datetime, precision: 3, limit: 2, scale: 1, default: -> { Time.now.utc }
@ -304,15 +295,6 @@ module ActiveRecord
assert_equal 123, model.non_existent_decimal assert_equal 123, model.non_existent_decimal
end end
test "attributes not backed by database columns keep their type when a default value is configured separately" do
child = Class.new(OverloadedType) do
attribute :non_existent_decimal, default: "123"
end
assert_equal OverloadedType.type_for_attribute("non_existent_decimal"), child.type_for_attribute("non_existent_decimal")
assert_equal 123, child.new.non_existent_decimal
end
test "attributes not backed by database columns properly interact with mutation and dirty" do test "attributes not backed by database columns properly interact with mutation and dirty" do
child = Class.new(ActiveRecord::Base) do child = Class.new(ActiveRecord::Base) do
self.table_name = "topics" self.table_name = "topics"