diff options
author | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2018-09-19 23:58:43 -0400 |
---|---|---|
committer | Rafael Mendonça França <rafaelmfranca@gmail.com> | 2018-09-20 00:03:15 -0400 |
commit | a0482d39110860272a056593e0e5c6e2ef4d75b8 (patch) | |
tree | 98428d16d28143d12372d0136674bfa86e56afe3 /activerecord | |
parent | e184d1a94e3ecfbc22823fbb9097992158a40cb2 (diff) | |
download | rails-a0482d39110860272a056593e0e5c6e2ef4d75b8.tar.gz rails-a0482d39110860272a056593e0e5c6e2ef4d75b8.tar.bz2 rails-a0482d39110860272a056593e0e5c6e2ef4d75b8.zip |
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.
Diffstat (limited to 'activerecord')
-rw-r--r-- | activerecord/lib/active_record/model_schema.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/attributes_test.rb | 14 |
2 files changed, 15 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/model_schema.rb b/activerecord/lib/active_record/model_schema.rb index 694ff85fa1..9b985e049b 100644 --- a/activerecord/lib/active_record/model_schema.rb +++ b/activerecord/lib/active_record/model_schema.rb @@ -375,7 +375,7 @@ module ActiveRecord # 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: diff --git a/activerecord/test/cases/attributes_test.rb b/activerecord/test/cases/attributes_test.rb index 3bc56694be..2632aec7ab 100644 --- a/activerecord/test/cases/attributes_test.rb +++ b/activerecord/test/cases/attributes_test.rb @@ -148,6 +148,20 @@ module ActiveRecord 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 |