更新 Rails 6.1
使用新的 Rails 版本,这变得很简单,如下所述:
.where.missing(:children)
对于旧版本,请参见下文。
导轨 3 和 4
scope :without_children, includes(:children).where(:children => { :id => nil })
这里最大的区别是joins
成为一个includes
:一个包含加载所有关系,如果它们存在,则连接将只加载关联的对象并忽略没有关系的对象。
实际上,scope :with_children, joins(:children)
应该足以返回至少有 1 个孩子的父母。试试看!
导轨 5
请参阅下面的@Anson 的答案
activerecord_where_assoc
gem 可以为 Rails 4.1 到 6.0 执行此操作。
scope :without_children, where_assoc_not_exists(:children)
自引用关系被无缝处理。
这也避免了诸如joins
使查询为单个记录返回多行等问题。
正如@MauroDias 指出的那样,如果它是您的父母和孩子之间的自我参照关系,那么上面的代码将不起作用。
通过一些研究,我发现了如何做到这一点:
考虑这个模型:
class Item < ActiveRecord::Base
has_many :children, :class_name => 'Item', :foreign_key => 'parent_id'
如何退回所有没有孩子的物品:
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 时会使用表。
类似的问题: