diff --git a/lib/extensions/ar_private_attribute.rb b/lib/extensions/ar_private_attribute.rb index 5beeba53ea75..8f3051f0e88c 100644 --- a/lib/extensions/ar_private_attribute.rb +++ b/lib/extensions/ar_private_attribute.rb @@ -9,6 +9,8 @@ module ArPrivateAttribute # @param [String|Symbol] attribute name of attribute to be private from the api and reporting # this attribute is accessible to all ruby methods. But it is not advertised. # we do this when deprecating an attribute or when introducing an internal attribute + # + # NOTE: only use in class definitions, or child classes will be broken def private_attribute(attribute) self.private_attribute_names += [attribute.to_s] end diff --git a/spec/lib/extensions/ar_private_attribute_spec.rb b/spec/lib/extensions/ar_private_attribute_spec.rb index e6c65e321081..3b6714037231 100644 --- a/spec/lib/extensions/ar_private_attribute_spec.rb +++ b/spec/lib/extensions/ar_private_attribute_spec.rb @@ -2,6 +2,7 @@ # NOTE: ApplicationRecord already included ArPrivateAttribute let(:klass) { Class.new(ApplicationRecord) { self.table_name = "vms" } } let(:other_klass) { Class.new(ApplicationRecord) { self.table_name = "vms" } } + let(:child_klass) { Class.new(klass) } context ".public_attribute_names" do it "shows regular attributes" do @@ -13,10 +14,51 @@ expect(klass.public_attribute_names).not_to include("type") end + it "shows virtual attributes" do + klass.virtual_attribute :superb, :string + expect(klass.public_attribute_names).to include("superb") + end + + it "hides private virtual attributes" do + klass.virtual_attribute :superb, :string + klass.private_attribute :superb + expect(klass.public_attribute_names).not_to include("superb") + end + it "only hides attributes for the specified class" do klass.private_attribute :type expect(other_klass.public_attribute_names).to include("type") end + + context "child class" do + it "shows regular attributes" do + expect(child_klass.public_attribute_names).to include("type") + end + + it "hides attributes that are private in parent class" do + klass.private_attribute :type + expect(child_klass.public_attribute_names).not_to include("type") + end + + it "hides virtual attributes that are private in the parent class" do + klass.virtual_attribute :superb, :string + klass.private_attribute :superb + expect(child_klass.public_attribute_names).not_to include("superb") + end + + it "hides attributes that are private in class and parent class" do + klass.private_attribute :type + child_klass.private_attribute :name + expect(child_klass.public_attribute_names).not_to include("type") + expect(child_klass.public_attribute_names).not_to include("name") + end + + it "hides attribute only for class and below" do + child_klass.private_attribute :name + expect(klass.public_attribute_names).to include("name") + expect(child_klass.public_attribute_names).not_to include("name") + end + end end context ".private_attribute_names" do @@ -33,5 +75,23 @@ klass.private_attribute :type expect(other_klass.private_attribute_names).not_to include("type") end + + context "child class" do + it "starts with no private attributes" do + expect(child_klass.private_attribute_names).to be_empty + end + + it "hides attributes that are private in parent class" do + klass.private_attribute :type + expect(child_klass.private_attribute_names).to include("type") + end + + it "hides attributes that are private in parent class" do + klass.private_attribute :type + child_klass.private_attribute :name + expect(child_klass.private_attribute_names).to include("type") + expect(child_klass.private_attribute_names).to include("name") + end + end end end diff --git a/spec/models/mixins/deprecation_mixin_spec.rb b/spec/models/mixins/deprecation_mixin_spec.rb index 7e059ef1c762..6077939616b1 100644 --- a/spec/models/mixins/deprecation_mixin_spec.rb +++ b/spec/models/mixins/deprecation_mixin_spec.rb @@ -7,4 +7,11 @@ expect(Host.arel_attribute(:address).name).to eq("hostname") # typically this is a symbol. not perfect but it works end end + + # Host.deprecate_attribute :address, :hostname + context ".public_attribute_names" do + it "hides deprecate_attribute columns" do + expect(Host.public_attribute_names).not_to include("address") + end + end end