Make a deep copy of the _default_attributes in column_defaults
When column_defaults is called it calls `value` on each instance of Attribute inside the _default_attributes set. Since value is memoized in the Attribute instance and that Attribute instance is shared across all instances of a model the next call to the default value will be memozied not running the proc defined by the user. Fixes #33031.
This commit is contained in:
parent
e184d1a94e
commit
a0482d3911
@ -375,7 +375,7 @@ def type_for_attribute(attr_name, &block)
|
||||
# default values when instantiating the Active Record object for this table.
|
||||
def column_defaults
|
||||
load_schema
|
||||
@column_defaults ||= _default_attributes.to_hash
|
||||
@column_defaults ||= _default_attributes.deep_dup.to_hash
|
||||
end
|
||||
|
||||
def _default_attributes # :nodoc:
|
||||
|
@ -148,6 +148,20 @@ def deserialize(*)
|
||||
assert_equal 2, klass.new.counter
|
||||
end
|
||||
|
||||
test "procs for default values are evaluated even after column_defaults is called" do
|
||||
klass = Class.new(OverloadedType) do
|
||||
@@counter = 0
|
||||
attribute :counter, :integer, default: -> { @@counter += 1 }
|
||||
end
|
||||
|
||||
assert_equal 1, klass.new.counter
|
||||
|
||||
# column_defaults will increment the counter since the proc is called
|
||||
klass.column_defaults
|
||||
|
||||
assert_equal 3, klass.new.counter
|
||||
end
|
||||
|
||||
test "procs are memoized before type casting" do
|
||||
klass = Class.new(OverloadedType) do
|
||||
@@counter = 0
|
||||
|
Loading…
Reference in New Issue
Block a user