aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Griffin <sean@thoughtbot.com>2014-12-08 12:45:21 -0700
committerSean Griffin <sean@thoughtbot.com>2014-12-08 12:48:24 -0700
commit7daeb98c769a3968a2ccf48ff593909bf1a9d7b0 (patch)
tree3f33df0a5f05b369b73f6a4680d9cfa06f21fe9d
parent4ed60af60d8b0ce6696f03d2d77916713c39af12 (diff)
downloadrails-7daeb98c769a3968a2ccf48ff593909bf1a9d7b0.tar.gz
rails-7daeb98c769a3968a2ccf48ff593909bf1a9d7b0.tar.bz2
rails-7daeb98c769a3968a2ccf48ff593909bf1a9d7b0.zip
Don't error when `attributes` is called on a frozen AR model
`freeze` will ultimately end up freezing the `AttributeSet`, which in turn freezes its `@attributes` hash. However, we actually insert a special object to lazily instantiate the values of the hash on demand. When it does need to actually instantiate all of them for iteration (the only case is `ActiveRecord::Base#attributes`, which calls `AttributeSet#to_h`), it will set an instance variable as a performance optimization Since it's just an optimization for subsequent calls, and that method being called at all is a very uncommon case, we can just leave the ivar alone if we're frozen, as opposed to coming up with some overly complicated mechanism for freezing which allows us to continue to modify ourselves. Fixes #17960
-rw-r--r--activerecord/lib/active_record/attribute_set/builder.rb4
-rw-r--r--activerecord/test/cases/attribute_set_test.rb8
2 files changed, 11 insertions, 1 deletions
diff --git a/activerecord/lib/active_record/attribute_set/builder.rb b/activerecord/lib/active_record/attribute_set/builder.rb
index 05138ae36d..3a76f5262d 100644
--- a/activerecord/lib/active_record/attribute_set/builder.rb
+++ b/activerecord/lib/active_record/attribute_set/builder.rb
@@ -76,7 +76,9 @@ module ActiveRecord
unless @materialized
values.each_key { |key| self[key] }
types.each_key { |key| self[key] }
- @materialized = true
+ unless frozen?
+ @materialized = true
+ end
end
delegate_hash
end
diff --git a/activerecord/test/cases/attribute_set_test.rb b/activerecord/test/cases/attribute_set_test.rb
index de63672963..ba53612d30 100644
--- a/activerecord/test/cases/attribute_set_test.rb
+++ b/activerecord/test/cases/attribute_set_test.rb
@@ -178,5 +178,13 @@ module ActiveRecord
builder = AttributeSet::Builder.new(foo: Type::Integer.new, bar: Type::Float.new)
builder.build_from_database(foo: '1.1')
end
+
+ test "freezing doesn't prevent the set from materializing" do
+ builder = AttributeSet::Builder.new(foo: Type::String.new)
+ attributes = builder.build_from_database(foo: "1")
+
+ attributes.freeze
+ assert_equal({ foo: "1" }, attributes.to_hash)
+ end
end
end