Rails 4可以找到没有孩子的父母

时间:2013-08-06 13:49:56

标签: ruby-on-rails rails-activerecord

我发现一个answer有一些可用的having示例,用于查找有n个孩子的父母,但同样不适用于找到没有孩子的父母(可能是因为加入排除它们)。

scope :with_children, joins(:children).group("child_join_table.parent_id").having("count(child_join_table.parent_id) > 0")

有人能指出我正确的方向吗?

3 个答案:

答案 0 :(得分:61)

这应该可以完成你想要的工作:

Rails 3& 4

scope :without_children, includes(:children).where(:children => { :id => nil })

这里最大的区别是joins成为includes:一个include加载所有关系,如果它们存在,则连接将仅加载关联的对象并忽略没有关系的对象。

事实上,scope :with_children, joins(:children)应足以让父母至少返回1个孩子。试试吧!

Rails 5

  

请参阅@ Anson的答案


正如@MauroDias所指出的那样,如果它是你父母和孩子之间的自我指涉关系,那么上面的代码将不起作用。

通过一些研究,我发现了如何做到这一点:

考虑这个模型:

class Item < ActiveRecord::Base
  has_many :children, :class_name => 'Item', :foreign_key => 'parent_id'

如何返回没有孩子的所有项目(ren):

Item.includes(:children).where(children_items: { id: nil })

我是如何找到children_items表的?

Item.joins(:children)生成以下SQL:

SELECT "items".* 
FROM "items" 
 INNER JOIN "items" "children_items" 
 ON "children_items"."parent_id" = "items"."id"

所以我猜测Rails在自引用的情况下需要JOIN时使用表。


类似问题:

答案 1 :(得分:19)

@MrYoshiji有一个坚实的Rails 4答案,但是对于那些来Rails 5的人来说,你有更多的选择。

使用Rails 5:

从Rails 5开始,您还可以使用http://example.com/scripts/script.php?id=uname来避免加载关联。它是在拉取请求left_outer_joins中引入的。

scope :without_children, left_outer_joins(:children).where(children: { id: nil })

对于有孩子的父母,MrYoshiji的Rails 4解决方案仍然可以使用:

scope :with_children, joins(:children)

答案 2 :(得分:1)

这就是我为Rails 5解决它的方法:

scope :without_comments, -> do
  left_outer_joins(:comments).where(comments: { id: nil })
end