You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 6.1自引用has_many关联中where.missing方法失效问题求解

Hey there! Let's work through this issue with Rails 6.1's where.missing and your self-referential Item associations. The problem here boils down to how Rails handles self-referential relationships and scoped associations with the missing method—let's fix those scopes step by step.

Fixing no_child_items

First, let's tackle the scope to find items with no child items. While where.missing(:child_items) should work in theory for self-referential has_many associations, sometimes Rails can have trouble resolving the table aliases correctly in this scenario. A more reliable (and equally clean) approach is to use the traditional left_joins + null check:

scope :no_child_items, -> { left_joins(:child_items).where(child_items: { id: nil }) }

This works by performing a left join to the child items, then filtering for records where the child item's ID is null—meaning no matching child records exist. If you still want to use where.missing, double-check that your child_items association is correctly defined (yours looks good!), and make sure you're running a recent patch version of Rails 6.1 (some early 6.1 releases had edge case bugs with self-referential missing).

Fixing no_approved_child_items

For scoped associations like approved_child_items, where.missing can struggle to apply the scope's conditions properly. Again, using left_joins is the most dependable solution, since it automatically inherits the scope from the association:

scope :no_approved_child_items, -> { 
  left_joins(:approved_child_items)
    .where(approved_child_items: { id: nil })
}

This will generate a left join that includes only approved child items, then filter for parent items where no such approved child exists. If you prefer a more explicit approach using exists?, you can also write it like this:

scope :no_approved_child_items, -> { 
  where.not(
    exists?(
      Item.approved.where("parent_item_id = items.id")
    )
  )
}

This directly checks that there are no approved items linked to the current parent item via parent_item_id.

Full Updated Model

Here's your complete model with the fixed scopes, plus a small recommendation for your belongs_to association (since it looks like items can exist without a parent):

class Item < ApplicationRecord
  belongs_to :parent_item, class_name: "Item", optional: true # Add optional: true if items can have no parent
  has_many :child_items, class_name: "Item", foreign_key: :parent_item_id
  has_many :approved_child_items, -> { approved }, class_name: "Item", foreign_key: :parent_item_id
  scope :approved, -> { where.not(approved_at: nil) }

  # Fixed scope for items with no child items
  scope :no_child_items, -> { left_joins(:child_items).where(child_items: { id: nil }) }

  # Fixed scope for items with no approved child items
  scope :no_approved_child_items, -> { 
    left_joins(:approved_child_items)
      .where(approved_child_items: { id: nil })
  }
end

Key Notes

  • Adding optional: true to belongs_to :parent_item is important if your application allows items to exist without a parent (Rails 5+ makes belongs_to required by default).
  • The left_joins approach is more universally reliable for self-referential and scoped associations, even if where.missing works in some cases.

内容的提问来源于stack exchange,提问作者sethherr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 04:34:06