我基本上是想做这样的事情:
class A < ActiveRecord::Base
has_many :bs
end
class B < ActiveRecord::Base
belongs_to :a
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b
has_many :ds
end
class D < ActiveRecord::Base
...
# and so on with class E, F, G, ...
# get all `C` for all `B` of `A` does not work
A.first.bs.cs
--> undefined method `cs' for #<ActiveRecord::Associations::CollectionProxy::ActiveRecord_Associations_CollectionProxy_B:0xxxxx>
我天真的方法是使用新功能来修补补丁数组,我们就像这样:
class Array
def get (m)
self.map{|o| o.send(m)}.delete_if(&:empty?).flatten
end
end
# works:
A.first.bs.get(:cs)
# works too:
A.all.get(:bs).get(:cs)
# works:
A.all.get(:bs).get(:cs).get(:ds).get(:es)
目前我还没有看到任何陷阱吗?用这样的函数修补Array
的猴子对我来说有点味道 - 有没有更干净的方法?
我只是想在我的代码中没有太多麻烦地链接那些has_many
- 关联。也许已经有了它的宝石我还没找到?
答案 0 :(得分:2)
首先,bs
方法返回的对象不是数组 - 它是一个更复杂的AssociationProxy
对象,它包含一个名为internal target
的数组。您的方法会导致N+1
问题的极端情况。
正确的方法是引入has_many :through
关联:
class A < ActiveRecord::Base
has_many :bs
has_many :cs, through: :bs
end
然后你可以打电话:
A.cs
db中没有任何变化。
如果你有更多的嵌套关联(让我们说C has_many:ds),你可以通过另一个has_many来获取它们:通过关联:
class A < ActiveRecord::Base
has_many :bs
has_many :cs, through: :bs
has_many :ds, through: :cs
end