From 2fe11e4cddfa0b1e7faa199bfd2279fed3b55d48 Mon Sep 17 00:00:00 2001 From: Matthew Draper Date: Wed, 14 May 2014 22:33:03 +0930 Subject: [PATCH] Merge pull request #14833 from jyao6/attribute_inheritance Fixed Attribute Inheritance Issue Conflicts: activerecord/CHANGELOG.md --- activerecord/CHANGELOG.md | 7 +++++++ activerecord/lib/active_record/store.rb | 19 ++++++++++++++----- activerecord/test/cases/store_test.rb | 16 ++++++++++++++++ 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 6f11170e85d5d..bdb7f9d74fb70 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Fix `stored_attributes` to correctly merge the details of stored + attributes defined in parent classes. + + Fixes #14672. + + *Brad Bennett*, *Jessica Yao*, *Lakshmi Parthasarathy* + * Fix bug where `ActiveRecord::Store` used a global `Hash` to keep track of all registered `stored_attributes`. Now every subclass of `ActiveRecord::Base` has it's own `Hash`. diff --git a/activerecord/lib/active_record/store.rb b/activerecord/lib/active_record/store.rb index b779ce7b50fd8..e250e9378e8df 100644 --- a/activerecord/lib/active_record/store.rb +++ b/activerecord/lib/active_record/store.rb @@ -61,8 +61,9 @@ module Store extend ActiveSupport::Concern included do - class_attribute :stored_attributes, instance_accessor: false - self.stored_attributes = {} + class << self + attr_accessor :local_stored_attributes + end end module ClassMethods @@ -88,9 +89,9 @@ def store_accessor(store_attribute, *keys) # assign new store attribute and create new hash to ensure that each class in the hierarchy # has its own hash of stored attributes. - self.stored_attributes = {} if self.stored_attributes.blank? - self.stored_attributes[store_attribute] ||= [] - self.stored_attributes[store_attribute] |= keys + self.local_stored_attributes ||= {} + self.local_stored_attributes[store_attribute] ||= [] + self.local_stored_attributes[store_attribute] |= keys end def _store_accessors_module @@ -100,6 +101,14 @@ def _store_accessors_module mod end end + + def stored_attributes + parent = superclass.respond_to?(:stored_attributes) ? superclass.stored_attributes : {} + if self.local_stored_attributes + parent.merge!(self.local_stored_attributes) { |k, a, b| a | b } + end + parent + end end protected diff --git a/activerecord/test/cases/store_test.rb b/activerecord/test/cases/store_test.rb index 47a6656fd536f..21dcf605e0b17 100644 --- a/activerecord/test/cases/store_test.rb +++ b/activerecord/test/cases/store_test.rb @@ -156,6 +156,22 @@ class StoreTest < ActiveRecord::TestCase assert_raise(NoMethodError) { @john.stored_attributes } end + test "stored_attributes are tracked per subclass" do + first_model = Class.new(ActiveRecord::Base) do + store_accessor :data, :color + end + second_model = Class.new(first_model) do + store_accessor :data, :width, :height + end + third_model = Class.new(first_model) do + store_accessor :data, :area, :volume + end + + assert_equal [:color], first_model.stored_attributes[:data] + assert_equal [:color, :width, :height], second_model.stored_attributes[:data] + assert_equal [:color, :area, :volume], third_model.stored_attributes[:data] + end + test "YAML coder initializes the store when a Nil value is given" do assert_equal({}, @john.params) end