From c3054b36216c6930e0eaa25c42625c8af5cdd7ed Mon Sep 17 00:00:00 2001 From: DarshanaVenkatesh <70602567+DarshanaVenkatesh@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:31:58 -0800 Subject: [PATCH] MONGOID-5816: attr_readonly leaks into sibling classes (backport for 8.1.) --- lib/mongoid/attributes/readonly.rb | 11 ++++++++--- spec/mongoid/attributes/readonly_spec.rb | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/mongoid/attributes/readonly.rb b/lib/mongoid/attributes/readonly.rb index 30f94d9851..8add225556 100644 --- a/lib/mongoid/attributes/readonly.rb +++ b/lib/mongoid/attributes/readonly.rb @@ -22,7 +22,7 @@ module Readonly # @return [ true | false ] If the document is new, or if the field is not # readonly. def attribute_writable?(name) - new_record? || (!readonly_attributes.include?(name) && _loaded?(name)) + new_record? || (!self.class.readonly_attributes.include?(name) && _loaded?(name)) end private @@ -62,12 +62,17 @@ module ClassMethods # end # # @param [ Symbol... ] *names The names of the fields. + # @note When a parent class contains readonly attributes and is then + # inherited by a child class, the child class will inherit the + # parent's readonly attributes at the time of its creation. + # Updating the parent does not propagate down to child classes after wards. def attr_readonly(*names) + self.readonly_attributes = self.readonly_attributes.dup names.each do |name| - readonly_attributes << database_field_name(name) + self.readonly_attributes << database_field_name(name) end end end end end -end +end \ No newline at end of file diff --git a/spec/mongoid/attributes/readonly_spec.rb b/spec/mongoid/attributes/readonly_spec.rb index 4476d06ccf..5da5237992 100644 --- a/spec/mongoid/attributes/readonly_spec.rb +++ b/spec/mongoid/attributes/readonly_spec.rb @@ -265,7 +265,26 @@ expect(child.mother).to be_nil end end + end + + context "when a subclass inherits readonly fields" do + let(:attributes) do + [:title, :terms] + end + + before do + class OldPerson < Person + attr_readonly :age + end + end + it "ensures subclass inherits the readonly attributes from parent" do + expect(OldPerson.readonly_attributes.to_a).to include("title","terms") + end + + it "ensures subclass does not modify parent's readonly attributes" do + expect(Person.readonly_attributes.to_a).not_to include("age") + end end end end