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, -> includes(:steps).where("steps.id IS NOT NULL")
及其对应的 scope :not_in_use, -> 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 查找所有有关联孩子的父母的主要内容,如果未能解决你的问题,请参考以下文章
查找父母的上一个兄弟姐妹的孩子(其中任何一个)是不是包含特定文本