2012-06-05 12 views
6

Ich habe ein Modell, das has_and_belongs_to_many :taxons, und ich möchte alle Produkte finden, die in bestimmten Taxonen sind.Suche Datensätze mit zwei bestimmten Datensätzen in einer anderen Tabelle

Zum Beispiel, wenn ein Produkt gehört sowohl die „Ruby on Rails“ und „T-Shirts“ Taxon, ich mag, dass das Produkt im Datensatz zurückgegeben werden, aber nicht wenn es gehört nur entweder „Ruby on Rails "oder‚Shirts‘

Antwort

13

ich hatte dieses Problem eine Weile zurück, zum Glück gibt es eine schöne Lösung.

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

Ein Internet für Sie, mein Herr. –

+0

@RyanBigg Werfen Sie auch einen Blick auf dieses Juwel: https://github.com/ernie/squeel. Es fügt eine Ebene der Abstraktion über ARel hinzu. Es ermöglicht Ihnen, präzisere/lesbarere Abfragen zu erstellen. Auch wenn "taxons.name.in taxons" oder "taxons.name >> taxons" nicht so viel besser ist als verschachtelte Hashes, werden Sie diese Verkettung zu schätzen wissen, wenn Sie jemals mehr als 2 Beitrittsebenen benötigen. Und Sie können Ihre 'have' Sachen dazu bringen,' arel_table' aufzurufen, wie: 'have {count (id) == some_size}'. – jdoe

0

Unter der Annahme, Leistung nicht erforderlich ist:

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

Diese Antwort von @samuel ist genau das, was ich suchte, aber ich wollte immer noch in der Lage sein, um Schlüsselwörter zur Suche zu liefern, während sie von Taxon1 UND Taxon2 und TaxonN Filterung. Ich brauche nie eine Taxon1 ODER Taxon2 Suche, also habe ich die folgenden Anpassungen vorgenommen. Es könnte einen weniger hacky Weg geben, um dies zu tun, aber es funktioniert gut für mich.

habe ich ein neues Produkt Umfang in /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 

dann den neuen Bereich verwendet sie durch Zugabe von

/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 

Jetzt kann ich die Standardsuche Helfer verwenden, um Produkte abrufen (was bedeutet, dass ich immer noch Schlüsselwörter liefern kann, usw. zusammen mit den mehreren Taxa):

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

Das funktioniert für mich und fühlte sich ziemlich schmerzlos. Ich bin jedoch offen für bessere Optionen.

Verwandte Themen