我的目标是在Rails的ActiveRecord中实现类似“has_many”的东西。我想更多地了解如何加载类/对象。
当我在下面使用“has_many”时会发生什么?
class Widget < MiniRecord
has_many :trinkets
end
让我们说这是“MiniRecord”的实现:
class MiniRecord
class << self
def has_many associated_model
@associations[:has_many] << associated_model_sym
end
end
def list_associations
do_stuff(@associations) # Where do I instantiate @associations?
end
end
我已经把它弄到了可行的地步,但是我有一些凌乱的代码,我想减少它。
我想了解这是如何工作的,但具体来说,我应该在哪里实例化@associations?
我希望能够在定义类(即静态变量)时定义的MiniRecord
子类中“声明”属性,然后再对这些属性进行操作。
答案 0 :(得分:3)
当你扩展MiniRecord
,比如说MyRecord
时,你得到了一个类层次结构图,如下所示(#SomeClass
是本征类或SomeClass
的单例类:
Class
|
MiniRecord --class--> #MiniRecord
| |
MyRecord --class--> #MyRecord
在list_associations
上定义了MiniRecord
方法,has_many
上定义了#MiniRecord
。
当您在has_many
的班级主体中致电MyRecord
时,它会首先在#MyRecord
中查找失败的方法。然后它会在#MiniRecord
中查找并找到定义。如果它以某种方式失败,它将在Class
中查找定义。这就是这种方法的工作原理。
关于问题
具体来说,我应该在哪里实例化@associations?
您有两种选择:
使用时初始化
def has_many associated_model
@associations ||= Hash.new{|h, k| h[k] = [] }
@associations[:has_many] << associated_model_sym
end
在创建后代类时初始化
class MiniRecord
def self.inherited klass
klass.instance_variable_set(:@associations, Hash.new{|h, k| h[k] = [] }
end
end
请注意,您无法直接访问实例方法@associations
中的list_associations
,因为它位于不同的范围内。您需要在@associations
上公开MiniRecord
,然后从那里获取值。
class MiniRecord
class << self
def has_many associated_model
@associations[:has_many] << associated_model
end
attr_reader :associations
end
def self.inherited klass
klass.instance_variable_set(:@associations, Hash.new{|h, k| h[k] = [] })
end
def list_associations
do_stuff(self.class.associations) # Where do I instantiate @associations?
end
def do_stuff sth
p sth
end
end
class MyRecord < MiniRecord
has_many :thrinks
end
r = MyRecord.new
r.list_associations
p MyRecord.associations