ActiveRecord найти всех родителей, у которых есть ассоциированные дети - PullRequest
10 голосов
/ 29 апреля 2010

Я не знаю, почему я не могу понять это, я думаю, это должно быть довольно просто. У меня есть две модели (см. Ниже). Я пытаюсь придумать названную область действия для SupplierCategory, в которой были бы найдены все категории поставщиков (включая поставщиков), которые являются ассоциированными поставщиками, не пусты.

Я пробовал прямое соединение, 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

Ответы [ 4 ]

12 голосов
/ 29 апреля 2010

Вот еще один подход:

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

Это работает, потому что Rails использует OUTER JOIN для предложения include. Если подходящих строк не найдено, запрос возвращает значения NULL для столбцов поставщика. Следовательно NOT NULL check возвращает совпадающие строки.

Рельсы 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
3 голосов
/ 29 апреля 2010

Более простая версия:

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

Если вы хотите использовать его часто, рассмотрите возможность использования counter_cache .

3 голосов
/ 29 апреля 2010
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
1 голос
/ 29 апреля 2010

Я верю, что это будет что-то вроде

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

Дайте мне знать, если это работает для вас.

Edit: Используя идею fl00r:

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

Я считаю, что это более быстрый путь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...