我的模型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一样,并且接受的答案都没有解决它(它只有一些父母或度假村)多个查询。)
答案 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')