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

余生颓废 提交于 2019-12-03 13:12:11

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

socjopata

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.

Ruby Racer

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!