Question

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.find_by_taxon(@taxon)

... but I'm not sure what goes into that last method (just made up the name).

Was it helpful?

Solution

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}

OTHER TIPS

@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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top