From 71a1106dcdc2d6cb483756bfc8548041ea43898c Mon Sep 17 00:00:00 2001 From: DarshanaVenkatesh <70602567+DarshanaVenkatesh@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:32:25 -0800 Subject: [PATCH] MONGOID-5816: attr_readonly leaks into sibling classes (backport for 9.0) --- 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 77db040bdb..0097bb6fd3 100644 --- a/lib/mongoid/attributes/readonly.rb +++ b/lib/mongoid/attributes/readonly.rb @@ -23,7 +23,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 @@ -63,12 +63,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 3b3b11730e..4d6a9fcbbe 100644 --- a/spec/mongoid/attributes/readonly_spec.rb +++ b/spec/mongoid/attributes/readonly_spec.rb @@ -266,7 +266,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