ActiveRecord находят всех родителей, которые связали детей

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

Я попробовал прямое, присоединяются, 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
10
задан brad 29 April 2010 в 12:01
поделиться

4 ответа

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

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

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

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
12
ответ дан 3 December 2019 в 20:03
поделиться
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
3
ответ дан 3 December 2019 в 20:03
поделиться

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

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

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

3
ответ дан 3 December 2019 в 20:03
поделиться

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

#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"

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

1
ответ дан 3 December 2019 в 20:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: