2012-06-05 18 views
6

Tengo un modelo Product que has_and_belongs_to_many :taxons, y quiero encontrar todos los productos que están en taxones específicos.Búsqueda de registros con dos registros específicos en otra tabla

Por ejemplo, si un producto pertenece tanto a la "Ruby on Rails" y "Camisas" taxón, quiero que el producto sea devuelto en el conjunto de datos, pero no si sólo pertenece tanto a "Ruby on Rails "o 'camisas'

Respuesta

13

he tenido este problema hace un tiempo, por suerte hay una buena solución.

def self.has_taxons(taxons) 
    id = arel_table[:id] 
    Product.joins(:taxons).where(taxons: { name: taxons }).group(id).having(id.count.eq(taxons.size)) 
end 
+1

Una internet para usted, señor. –

+0

@RyanBigg También eche un vistazo a esta joya: https://github.com/ernie/squeel. Agrega una capa de abstracción sobre ARel. Le permite crear consultas más concisas/legibles. Incluso si 'taxons.name.in taxons' o' taxons.name >> taxons' no es mucho mejor que hashes anidados, apreciará este encadenamiento si alguna vez necesita más de 2 niveles de unión. Y usted puede hacer que su 'having' cosas sin llamar' arel_table', como: 'que tiene {count (id) == some_size}'. – jdoe

0

rendimiento Suponiendo que no es un requisito:

a = Taxon.find_by_name!('Ruby on Rails').products.pluck(:id) 
b = Taxon.find_by_name!('Shirts').products.where(:id => a) 
1

Esta respuesta de @samuel es exactamente lo que estaba buscando, pero quería ser capaz de suministrar todavía palabras clave para la búsqueda filtrando por Taxon1 Y Taxon2 y TaxonN. No necesito hacer una búsqueda de Taxon1 o Taxon2, así que realicé las siguientes personalizaciones. Puede haber una forma menos hacky de hacer esto, pero funciona muy bien para mí.

I añadió un nuevo ámbito de aplicación de producto en /app/models/spree/product_decorator.rb

Spree::Product.class_eval do 
    add_search_scope :in_all_taxons do |*taxons| 
     taxons = get_taxons(taxons) 
     id = arel_table[:id] 
     joins(:taxons).where(spree_taxons: { id: taxons }).group(id).having(id.count.eq(taxons.size)) 
    end 
end 

luego se usa el nuevo ámbito añadiéndolo a /app/models/spree/base_decorator.rb

Spree::Core::Search::Base.class_eval do 
    def get_base_scope 
     base_scope = Spree::Product.active 
     base_scope = base_scope.in_all_taxons(taxon) unless taxon.blank? 
     base_scope = get_products_conditions_for(base_scope, keywords) 
     base_scope = add_search_scopes(base_scope) 
     base_scope 
    end 
end 

Ahora puede utilizar el estándar ayudante de búsqueda para recuperar los productos (lo que significa que todavía puede suministrar palabras clave, etc, junto con las múltiples taxones):

# taxon_ids is an array of taxon ids 
@searcher = build_searcher(params.merge(:taxon => taxon_ids)) 
@products = @searcher.retrieve_products 

Esto funciona para mí y me sentí bastante indoloro. Sin embargo, estoy abierto a mejores opciones.

Cuestiones relacionadas