【问题标题】:activerecord chained has_many finderactiverecord 链式 has_many 查找器
【发布时间】:2014-01-15 11:20:21
【问题描述】:

我基本上是在尝试做这样的事情:

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-associations。也许已经有一个我还没有找到的宝石?

【问题讨论】:

  • 也许has_many :cs, through: :bs?
  • 你为什么不检查 has_many :通过选项
  • 明确表示它可以进一步下降,而不仅仅是两个级别,所以我认为through 不适用于从 A 到 E?

标签: ruby activerecord has-many


【解决方案1】:

首先,bs 方法返回的对象不是数组——它要复杂得多AssociationProxy 对象,它包装了一个内部称为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 :through 关联来获取它们:

class A < ActiveRecord::Base
  has_many :bs
  has_many :cs, through: :bs
  has_many :ds, through: :cs
end

【讨论】:

  • 是的,忘了提N+1 :)
  • 如果有更多的关联怎么办? C has_many D, D has_many E etc. 如何从 A 到 E?
  • 谢谢,我没想过简单地链接throughs
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 2011-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多