2010-04-29 11 views
10

No sé por qué no puedo resolver esto, creo que debería ser bastante simple. Tengo dos modelos (ver a continuación). Estoy tratando de llegar a un alcance definido para SupplierCategory que encuentre que todas las categorías de proveedores (incluidos los proveedores) cuyos proveedores asociados no estén vacíos.ActiveRecord encontrar todos los padres que tienen hijos asociados

que intentaron una hacia arriba se unen, named_scope :with_suppliers, :joins => :suppliers que me da únicas categorías con los proveedores, pero me da cada una de las categorías enumeradas por separado, por lo que si una categoría tiene 2 proveedores, i obtener la categoría de dos veces en la matriz devuelta:

Actualmente estoy usando:

named_scope :with_suppliers, :include => :suppliers 

y luego en mi opinión que estoy usando:

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

No exactamente, pero elocuente illustrat Es lo que estoy tratando de lograr.

Definición de Clases

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

class Supplier < AR 
    belongs_to :supplier 
end 
+0

En clase '' Subbplier' que quería decir belongs_to: supplier_category'? – klew

Respuesta

12

Aquí es un enfoque más:

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

Esto funciona porque utiliza los carriles OUTER unirse de forma include cláusula. Cuando no se encuentran filas coincidentes, la consulta arroja valores NULOS para las columnas del proveedor. Por lo tanto, NOT NULL check devuelve las filas coincidentes.

Carriles 4

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

o el uso de un método estático:

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

Nota:

esta solución cargas ansiosos proveedores.

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

sin duda la más sucinta de todas las soluciones y funciona perfectamente !! Gracias – brad

+1

Actualización para los carriles 4: 'alcance: en_uso, -> {incluye (: pasos) .donde ("steps.id NO ES NULO")}' y su contraparte 'alcance: not_in_use, -> { incluye (: pasos) .donde ("steps.id IS NULL")} ' – soychicka

1

creo que sería algo así como

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

Avísame si funciona para usted.

Editar: Usando la idea de fl00r:

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

Creo que esta es la manera más rápida.

+1

¿Seguro que puedes usar formas singulares de supplier_category modelo en lugar de supplier_categories? – fl00r

+0

no = P tks para eso. –

3
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 

Otra forma más flexible usando 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 
+0

Creo con el 'join' es más rápido, ¿verdad? No sé si es relevante en este caso ... pero tengo curiosidad = P –

+0

sí, tienes razón, por lo que ha añadido solución con unirse a – fl00r

+1

Su código devolverá datos duplicados debido a la unión. –

3

versión más simple:

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

Si desea utilizarlo con frecuencia, considere el uso de counter_cache.

+0

1 concisa .... –

Cuestiones relacionadas