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

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:
Rafael Mendonça França 2018-09-19 23:58:43 -04:00
parent e184d1a94e
commit a0482d3911
No known key found for this signature in database
GPG key ID: FC23B6D0F1EEE948
2 changed files with 15 additions and 1 deletions

View file

@ -375,7 +375,7 @@ module ActiveRecord
# default values when instantiating the Active Record object for this table. # default values when instantiating the Active Record object for this table.
def column_defaults def column_defaults
load_schema load_schema
@column_defaults ||= _default_attributes.to_hash @column_defaults ||= _default_attributes.deep_dup.to_hash
end end
def _default_attributes # :nodoc: def _default_attributes # :nodoc:

View file

@ -148,6 +148,20 @@ module ActiveRecord
assert_equal 2, klass.new.counter assert_equal 2, klass.new.counter
end 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 test "procs are memoized before type casting" do
klass = Class.new(OverloadedType) do klass = Class.new(OverloadedType) do
@@counter = 0 @@counter = 0