ActiveRecord 查找所有有关联孩子的父母

Posted

技术标签:

【中文标题】ActiveRecord 查找所有有关联孩子的父母【英文标题】:ActiveRecord find all parents that have associated children 【发布时间】:2010-04-29 12:01:43 【问题描述】:

我不知道为什么我无法弄清楚这一点,我认为它应该相当简单。我有两个模型(见下文)。我正在尝试为 SupplierCategory 提出一个命名范围,它会发现所有与 Supplier(s) 关联的 SupplierCategory(s)(包括:suppliers)都不为空。

我尝试了直接加入 named_scope :with_suppliers, :joins => :suppliers,它只给我提供了供应商的类别,但它给了我单独列出的每个类别,所以如果一个类别有 2 个供应商,我会在返回的数组中两次获得该类别:

目前我正在使用:

named_scope :with_suppliers, :include => :suppliers

然后在我看来我正在使用:

<%= render :partial => 'category', :collection => @categories.find_all|c| !c.suppliers.empty?  %>

不完全是雄辩的,但说明了我想要实现的目标。

类定义

class SupplierCategory < AR
  has_many :suppliers, :order => "name"
end

class Supplier < AR
  belongs_to :supplier
end

【问题讨论】:

Subbplier 类中你的意思是belongs_to :supplier_category 【参考方案1】:

这是另一种方法:

named_scope :with_suppliers, :include    => :suppliers, 
                             :conditions => "suppliers.id IS NOT NULL"

这是因为 Rails 使用 OUTER JOIN 作为 include 子句。当没有找到匹配的行时,查询返回供应商列的 NULL 值。因此NOT NULL check 返回匹配的行。

Rails 4

scope :with_suppliers,  includes(:steps).where("steps.id IS NOT NULL") 

或者使用静态方法:

def self.with_suppliers
  includes(:steps).where("steps.id IS NOT NULL")
end

注意:

此解决方案急切地加载供应商。

categories = SupplierCategory.with_suppliers
categories.first.suppliers #loaded from memory

【讨论】:

绝对是所有解决方案中最简洁的,并且完美运行!谢谢 为 rails 4 更新:scope :in_use, -&gt; includes(:steps).where("steps.id IS NOT NULL") 及其对应的 scope :not_in_use, -&gt; includes(:steps).where("steps.id IS NULL")【参考方案2】:
class SupplierCategory < AR
  has_many :supliers

  def self.with_supliers
    self.all.reject |c| c.supliers.empty? 
  end
end

SupplierCategory.with_supliers
#=> Array of SuplierCategories with supliers

使用 named_scope 的另一种更灵活的方式

class SupplierCategory < AR
  has_many :supliers
  named_scope :with_supliers, :joins => :supliers, :select => 'distinct(suplier_categories.id), suplier_categories.*', :having => "count(supliers.id) > 0"
end

SupplierCategory.with_supliers(:all, :limit => 4)
#=> first 4 SupplierCategories with suppliers

【讨论】:

我相信使用join 会更快,不是吗?我不知道这是否与他的情况有关……但我很好奇=P【参考方案3】:

更简单的版本:

named_scope :with_suppliers, :joins => :suppliers, :group => :id

如果你想经常使用,可以考虑使用counter_cache。

【讨论】:

【参考方案4】:

我相信会是这样的

#model SupplierCategory
named_scope :with_suppliers, 
   :joins => :suppliers,
   :select => "distinct(supplier_categories), supplier_categories.*",
   :conditions => "suppliers.supplier_categories_id = supplier_categories.id"

让我知道它是否适合你。

编辑: 使用fl00r的思路:

named_scope :with_suppliers, 
   :joins => :suppliers,
   :select => "distinct(supplier_categories), supplier_categories.*",
   :having => "count(supliers.id) > 0"

我相信这是更快的方法。

【讨论】:

您确定应该使用模型供应商类别的单数形式而不是供应商类别吗?

以上是关于ActiveRecord 查找所有有关联孩子的父母的主要内容,如果未能解决你的问题,请参考以下文章

jquery选择器需要选择父母的所有某些孩子

在平行继承层次结构中通过父母关联孩子

查找孩子的***父母,多个级别

查找父母的上一个兄弟姐妹的孩子(其中任何一个)是不是包含特定文本

查找具有多个 ActiveRecord HABTM 关联的记录

Mybatis双向关联