This is probably something very simple but I'm looking for the optimal way of retrieving all Products by Tag, so to speak. This is with Spree, so I should stick to the way they have modeled their data. It's actually Product
and Taxon
(like category, brand, etc.)
So if Product has_and_belongs_to_many :taxons
and Taxon has_and_belongs_to_many :products
, what's the best way to find all products by a Taxon?
Something like:
@taxon = Taxon.find_by_permalink('categories/')
@products = Product.f开发者_运维技巧ind_by_taxon(@taxon)
... but I'm not sure what goes into that last method (just made up the name).
Probably you're going to just simply say if there's only one Taxon
@products = @taxon.products
If there's multiple we require a slightly different method. But even then you could just
@products = @taxons.inject([]) {|taxon| taxon.products}
@taxon = Taxon.find_by_permalink('categories', :include => :products)
This will eager-load the products so you can access them through
@taxon.products
without it hitting the database again. This is the more efficient form of just using .products that avoids N+1 query problems.
Won't Taxon.find_by_permalink('categories/').products
suffice?
EDIT: Oh and for multiple taxons you could try something like this:
Product.find(:all, :include => :products_taxons, :conditions => { :products_taxons => {:taxon_id => [1,2,3]} }) # will find products with taxons with id 1, 2 or 3
I was able to get this working in Spree 2.1.0.beta with the following customizations:
Based on the answer here: Finding records with two specific records in another table
I added a new product scope 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
Then used the new scope by adding it to /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
Now I can use the standard search helper to retrieve products (which means I can still supply keywords, etc along with the multiple taxons):
# taxon_ids is an array of taxon ids
@searcher = build_searcher(params.merge(:taxon => taxon_ids))
@products = @searcher.retrieve_products
This works for me and felt pretty painless. However, I'm open to better options.
If you want to find a product by its tags you can use tagged_with
Example
Spree::Product.tagged_with("example")
Will return the products with the tag "example"
Source: https://github.com/mbleigh/acts-as-taggable-on
精彩评论