提交 eecfa84a 编写于 作者: J Jon Leighton

Always generate attribute methods on the base class.

This fixes a situation I encountered where a subclass would cache the
name of a generated attribute method in @_defined_class_methods. Then,
when the superclass has it's attribute methods undefined, the subclass
would always have to dispatch through method_missing, because the
presence of the attribute in @_defined_class_methods would mean that it
is never generated again, even if undefine_attribute_methods is called
on the subclass.

There various other confusing edge cases like this. STI classes share
columns, so let's just keep all the attribute method generation state
isolated to the base class.
上级 50d395f9
......@@ -11,17 +11,30 @@ module ClassMethods
# accessors, mutators and query methods.
def define_attribute_methods
return if attribute_methods_generated?
super(column_names)
@attribute_methods_generated = true
if base_class == self
super(column_names)
@attribute_methods_generated = true
else
base_class.define_attribute_methods
end
end
def attribute_methods_generated?
@attribute_methods_generated ||= false
if base_class == self
@attribute_methods_generated ||= false
else
base_class.attribute_methods_generated?
end
end
def undefine_attribute_methods(*args)
super
@attribute_methods_generated = false
if base_class == self
super
@attribute_methods_generated = false
else
base_class.undefine_attribute_methods(*args)
end
end
# Checks whether the method is defined in the model or any of its subclasses
......
......@@ -1332,7 +1332,7 @@ def compute_type(type_name)
# Returns the class descending directly from ActiveRecord::Base or an
# abstract class, if any, in the inheritance hierarchy.
def class_of_active_record_descendant(klass)
if klass.superclass == Base || klass.superclass.abstract_class?
if klass == Base || klass.superclass == Base || klass.superclass.abstract_class?
klass
elsif klass.superclass.nil?
raise ActiveRecordError, "#{name} doesn't belong in a hierarchy descending from ActiveRecord"
......
......@@ -35,6 +35,7 @@ def self.columns_hash
end
def self.serialized_attributes; {}; end
def self.base_class; self; end
end
end
......
......@@ -659,6 +659,22 @@ def test_list_of_serialized_attributes
assert_equal %w(preferences), Contact.serialized_attributes.keys
end
def test_instance_method_should_be_defined_on_the_base_class
subklass = Class.new(Topic)
Topic.define_attribute_methods
instance = subklass.new
instance.id = 5
assert_equal 5, instance.id
assert subklass.method_defined?(:id), "subklass is missing id method"
Topic.undefine_attribute_methods
assert_equal 5, instance.id
assert subklass.method_defined?(:id), "subklass is missing id method"
end
private
def cached_columns
@cached_columns ||= (time_related_columns_on_topic + serialized_columns_on_topic).map(&:name)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册