Skip to content

Commit

Permalink
Revert "Merge pull request rails#39929 from jonathanhefner/decorate-o…
Browse files Browse the repository at this point in the history
…riginal-attribute-type"

This reverts commit 79d0c17, reversing
changes made to bc828f7.

Fixes rails#41138.
  • Loading branch information
kamipo committed Jan 16, 2021
1 parent b5ab89b commit 5fc0c4c
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def serialize(attr_name, class_name_or_coder = Object, **options)
Coders::YAMLColumn.new(attr_name, class_name_or_coder)
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)
raise ColumnNotSerializableError.new(attr_name, cast_type)
end
Expand Down
55 changes: 33 additions & 22 deletions activerecord/lib/active_record/attributes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -208,21 +208,14 @@ module ClassMethods
# tracking is performed. The methods +changed?+ and +changed_in_place?+
# will be called from ActiveModel::Dirty. See the documentation for those
# 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
reload_schema_from_cache

prev_cast_type, prev_options, prev_decorator = attributes_to_define_after_schema_loads[name]

unless cast_type && prev_cast_type
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]
)
self.attributes_to_define_after_schema_loads =
attributes_to_define_after_schema_loads.merge(
name => [cast_type || block, options]
)
end

# This is the low level API which sits beneath +attribute+. It only
Expand Down Expand Up @@ -255,16 +248,8 @@ def define_attribute(

def load_schema! # :nodoc:
super
attributes_to_define_after_schema_loads.each do |name, (type, options, decorator)|
if type.is_a?(Symbol)
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))
attributes_to_define_after_schema_loads.each do |name, (type, options)|
define_attribute(name, _lookup_cast_type(name, type, options), **options.slice(:default))
end
end

Expand All @@ -287,6 +272,32 @@ def define_default_attribute(name, value, type, from_user:)
end
_default_attributes[name] = default_attribute
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
2 changes: 1 addition & 1 deletion activerecord/lib/active_record/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def enum(definitions)

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

Expand Down
18 changes: 0 additions & 18 deletions activerecord/test/cases/attributes_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,15 +68,6 @@ class CustomPropertiesTest < ActiveRecord::TestCase
assert_equal "the overloaded default", klass.new.overloaded_string_with_limit
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
klass = Class.new(OverloadedType) do
attribute :starts_at, :datetime, precision: 3, limit: 2, scale: 1, default: -> { Time.now.utc }
Expand Down Expand Up @@ -304,15 +295,6 @@ def deserialize(*)
assert_equal 123, model.non_existent_decimal
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
child = Class.new(ActiveRecord::Base) do
self.table_name = "topics"
Expand Down

0 comments on commit 5fc0c4c

Please sign in to comment.