From 54b157442171d28c7e9553537aef7a6ae571aad7 Mon Sep 17 00:00:00 2001 From: Josh Brody Date: Mon, 16 Sep 2019 16:57:47 -0500 Subject: [PATCH] Raise FrozenError for frozen objects when trying to write to a non-database-backed attribute. Writing to database-backed attributes after freezing an object would raise FrozenError, but wouldn't raise FrozenError for user-defined attributes. Fixes #37208 --- activemodel/CHANGELOG.md | 11 +++++++++++ activemodel/lib/active_model/attributes.rb | 1 + activemodel/test/cases/attributes_test.rb | 7 +++++++ 3 files changed, 19 insertions(+) diff --git a/activemodel/CHANGELOG.md b/activemodel/CHANGELOG.md index c301f4766d..d1f38ec760 100644 --- a/activemodel/CHANGELOG.md +++ b/activemodel/CHANGELOG.md @@ -1,3 +1,14 @@ +* Raise FrozenError when trying to write attributes that aren't backed by the database on an object that is frozen: + + class Animal + include ActiveModel::Attributes + attribute :age + end + + animal = Animal.new + animal.freeze + animal.age = 25 # => FrozenError, "can't modify a frozen Animal" + * Add *_previously_was attribute methods when dirty tracking. Example: pirate.update(catchphrase: "Ahoy!") diff --git a/activemodel/lib/active_model/attributes.rb b/activemodel/lib/active_model/attributes.rb index c586f52b78..453041559a 100644 --- a/activemodel/lib/active_model/attributes.rb +++ b/activemodel/lib/active_model/attributes.rb @@ -48,6 +48,7 @@ module ActiveModel ) do |temp_method_name, attr_name_expr| generated_attribute_methods.module_eval <<-RUBY, __FILE__, __LINE__ + 1 def #{temp_method_name}(value) + raise FrozenError, "can't modify frozen #{self.class.name}" if frozen? name = #{attr_name_expr} write_attribute(name, value) end diff --git a/activemodel/test/cases/attributes_test.rb b/activemodel/test/cases/attributes_test.rb index af0ddcb92f..364026ddd9 100644 --- a/activemodel/test/cases/attributes_test.rb +++ b/activemodel/test/cases/attributes_test.rb @@ -107,5 +107,12 @@ module ActiveModel assert_equal attributes, new_attributes end + + test "can't modify attributes if frozen" do + data = ModelForAttributesTest.new + data.freeze + assert data.frozen? + assert_raise(FrozenError) { data.integer_field = 1 } + end end end