使用Rails包含对孩子的条件

时间:2015-08-25 15:28:08

标签: ruby-on-rails rails-activerecord

我的模型Parent有很多孩子Child。我想得到所有的父模型并显示父项的每个Child。就我所知,这是Rails'includes方法的经典用例。

但是,我不能让Rails为子模型添加条件而不将Parent模型限制为有子模型的那些。

例如,这只输出有孩子的父母:

Parent.includes(:children).where(children: {age: 10}).each do |parent|
  # output parent info
  parent.children.where("age = 10").each do |child|
   #output child info
  end
end

我看过Rails includes with conditions但似乎我遇到的问题与问题的OP一样,并且接受的答案都没有解决它(它只有一些父母或度假村)多个查询。)

5 个答案:

答案 0 :(得分:4)

您需要使用LEFT JOIN

Parent.joins("LEFT JOIN children ON parent.id = children.parent_id")
      .where("parent.age = 10 AND children.age = 10")
      .select("parent.*, children.*")

如果要从parent表中选择可能有或没有children表中相应行的行,请使用LEFT JOIN子句。如果children表中没有匹配的行,则children表中的列值将替换为NULL值。

答案 1 :(得分:2)

这是包含方法的限制。你需要的是一个外连接,不幸的是,rails没有一个很好的方法来强制外连接而不使用原始的sql语法(#joins默认为内连接和#includes急切加载。) 尝试使用

的内容
Parent.joins('LEFT OUTER JOIN child on child.parent_id = parent.id').where(...)

这应该抓住所有父母,即使是那些没有孩子的父母

答案 2 :(得分:2)

我遇到了这个问题,因此绊倒了这个问题。可悲的是,到目前为止,没有一个答案是解决方案。很高兴,我找到了解决方案!部分感谢文档:) http://apidock.com/rails/ActiveRecord/QueryMethods/includes

正如文档所暗示的那样,仅仅包括关联,然后添加一个条件是不够的;你还必须参考"关联references(:children)

现在,另外你可以看到我使用了一些我建议在你的条件下合并的语法糖,而不是重写它们。尽可能使用它。

Parent.includes(:children).merge(Child.at_school).references(:children).first

所以我做了什么,我建议做的是为此设置一个范围:

class Parent < ActiveRecord::Model

    has_many :children

    scope :with_children_at_school, -> { includes(:children).merge(Child.at_school).references(:children) }
    # ...
end

然后你可以打电话给Parent.with_children_at_school.first(或者你想要连结的其他任何东西!

我希望这有帮助!

答案 3 :(得分:1)

这不是100%的答案,但是一种方法是接受您将获得所有由急切加载返回的子记录,但是要使用非ActiveRecord方法选择您想要的那些。

您将在急切的加载中包含比您需要的更多子记录,因此效率低于完美的解决方案,但您仍然可以获得所需的记录:

Parent.includes(:children).each do |parent|
  parent.children.select{|child| child.age == 10}.each do |child|
    blah blah...
  end
end

我假设您在选择标准上需要很大的灵活性,并且基于范围的关联不会提供这样的灵活性。

答案 4 :(得分:0)

没有孩子的父母会有一个孩子。为NULL,你只是为孩子过滤.age = 10.

尝试

where('children.age = 10 or children.age is null')