【问题标题】:Return Every Parent Relationship and filter children in where clause active record返回每个父关系并在 where 子句活动记录中过滤子项
【发布时间】:2015-11-14 23:42:45
【问题描述】:

我有父母,孩子,技能的关系。每个父母可以有几个孩子,每个孩子都有一项技能。

我想从数据库中返回所有父母,如果他们有一定的技能,包括属于他们的孩子。

在查询结束时,我们将有几个可能有 0 个孩子的父母。我正在尝试类似Parent.includes(children: [:skill]).where(skill: {skill_type: type}) 的东西,但这并没有返回所有的父母。这可以通过 ActiveRecord 完成吗?

【问题讨论】:

  • 真的是skillType 而不是skill_type?前者非常独特。

标签: ruby-on-rails ruby activerecord


【解决方案1】:
class Parent < ActiveRecord::Base
  has_many :children
  has_many :skills, through: :children
  def self.with_skill(skill_type)
    children = Child.joins(:skills).where(skills: { skill_type: skill_type } )
    Parent.all.map do |parent|
      children = children.select { |c| c.parent_id == parent.id }
      # This marks the association as loaded so that rails does not issue a n+1 query
      association = parent.association(:children)
      association.loaded!
      association.target.concat(children)
      children.each { |c| association.set_inverse_instance(c) }
      parent.readonly! # because we dont want to accidentally set the children to []
      parent
    end
  end
end

这里我们使用两个查询,第一个获取所有具有所选技能和技能的孩子。第二个得到所有的父母。

然后我们手动设置 Parent 和 Child 之间的关系,以便 parent.children 不会导致 ActiveRecord 查询数据库中的子项。

我们还将记录标记为只读,因为如果保存其中一条记录,它可能会从关联的子项中删除 parent_id

总而言之,这是一种变通方法,可以很好地显示记录。 Rails 并没有真正让您准确地选择应该以您希望的方式预加载的关联。

【讨论】:

  • 感谢您付出的大量努力。除了我总是想返回所有父母之外,它与我正在寻找的东西很接近,但如果他们的孩子没有技能,请不要将他们包含在 Parent 对象下。因此,如果 Parent 'parent2' 有一个具有拖延技能的孩子并且我们寻找具有 'sneaking' 技能的孩子,它将返回没有孩子的 parent2,而不是一个空的活动记录关系。
  • 我使用解决方法对其进行了编辑-您可以使用自定义查询构建joins,但由于预加载的工作方式,它仍然会导致每个父级 n+1。我已经创建了一个问题,您是否可以在此处使用 eager_load stackoverflow.com/questions/33716153/…
  • 谢谢我现在正在使用解决方案。我需要能够返回 JSON 响应,并且如果他们没有任何具有技能的孩子,则为父母显示一个空的孩子数组。现在我仍然在 JSON 响应中返回所有结果,但可能是我正在做的一些愚蠢的事情。
  • 你可以这样做gist.github.com/maxcal/254aaa3cc790d1b8fda0。由于您是在 Ruby 中而不是在数据库中迭代记录,因此不确定大型集的性能。
  • 已编辑。当我无法让 Rails 以我想要的方式加载关联时,我使用了这个。它基本上是 Rails 加入并包含方法加载相关记录的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多