get all products of category and child categories (rails, awesome_nested_set)

前端 未结 3 1517
孤街浪徒
孤街浪徒 2021-02-15 14:50

having an e-commerce application under development i am trying to get my head around the following problem: I have my categories realized through the awesome_nested_set plugin.

相关标签:
3条回答
  • 2021-02-15 15:26

    Extending charlysisto 's answer, when you are dealing with has_and_belongs_to_many categories, you will soon find out that the brute force perspective is quite slow... You need some kind of "middleware" to make it faster...

    socjopata 's answer gives a good approach of how to improve this. So, you use the definition

    def branch_ids
      self_and_descendants.map(&:id).uniq 
    end
    

    in your category.rb file (model).

    Then, for example, in your controller (example with pagination):

    @category = Category.find... # whatever
    branches  = @category.branch_ids
    @prodcats = ProductCategory.select('distinct product_id')
                               .where('category_id IN (?)',branches)
                               .order(:product_id)
                               .paginate(page: params[:page], :per_page => 25)
    ids       = @prodcats.map(&:product_id)
    @products = Product.where('id IN (?)', ids)
    

    Finally, in your view, you will need a little "technique" in order to have pagination. You will paginate on @prodcats, not @products...

    <%= will_paginate @prodcats %>
    <% @products.each do |product| %>
        ....
    <% end %>
    

    This approach is way faster, WHEN DEALING WITH many_to_many, though not 100% politically correct, I must admit.

    0 讨论(0)
  • 2021-02-15 15:36

    There are a several ways you could improve your code, but if you're looking for all products that belong to a category and children (descendants) of the category then why you won't do it like this:

    def branch_ids
      self_and_descendants.map(&:id).uniq 
    end
    
    def all_products
      Product.find(:all, :conditions => { :category_id => branch_ids } )
    end
    

    I've done some assumptions here, but I hope you get the idea.

    0 讨论(0)
  • 2021-02-15 15:53

    The key with awesome_nested_set is to use a range in the lft column. Here's a code sample of how I do it with a direct association (category has_many articles)

      module Category
        extend ActiveSupport::Concern
        included do
          belongs_to :category
          scope :sorted, includes(:category).order("categories.lft, #{table_name}.position")
        end
    
        module ClassMethods
          def tree(category=nil) 
            return scoped unless category
            scoped.includes(:category).where([
              "categories.tree_id=1 AND categories.lft BETWEEN ? AND ?", 
              category.lft, category.rgt
            ])
          end
        end # ClassMethods
      end
    

    Then somewhere in a controller

    @category = Category.find_by_name("fruits")
    @articles = Article.tree(@category) 
    

    that will find all articles under the categories apples, oranges, bananas, etc etc. You should adapt that idea with a join on categorizations (but are you sure you need a many to many relationship here?)

    Anyway I would try this :

    class Product < AR
          has_many :categorizations
    
          def self.tree(category=nil) 
            return scoped unless category
            select("distinct(products.id), products.*").
            joins(:categorizations => :category).where([
              "categories.lft BETWEEN ? AND ?", category.lft, category.rgt
            ])
          end
    end
    

    Let me know if there's any gotcha

    0 讨论(0)
提交回复
热议问题