получить все товары категории и дочерних категорий (rails, awesome_nested_set) - PullRequest
8 голосов
/ 07 сентября 2011

разрабатывая приложение для электронной коммерции, я пытаюсь разобраться со следующей проблемой: мои категории реализованы с помощью плагина awesome_nested_set.Если я перечисляю свои статьи путем выбора одной категории, все работает нормально, но для некоторых ссылок я хочу показать все продукты одной категории и продукты ее дочерних категорий.

вот код контроллера, который отлично работает столько одна категория:

   # products_controller.rb
   def index
    if params[:category]
      @category = Category.find(params[:category])
      #@products = @category.product_list
      @products = @category.products
    else
      @category = false
      @products = Product.scoped
    end
    @products = @products.where("title like ?", "%" + params[:title] + "%") if params[:title]
    @products = @products.order("created_at).page(params[:page]).per( params[:per_page] ? params[:per_page] : 25)
    @categories = Category.all
  end

Закомментированная строка является вспомогательным методом, который я сам написал в модели категорий, которая возвращает все продукты категории и ее дочерних категорий в массиве.

Это определяется следующим образом:

# app/models/category.rb
def product_list
  self_and_ancestors.to_a.collect! { |x| x.products }
end

Теперь, когда я раскомментирую эту строку и попытаюсь выбрать одну категорию, код моего продукта прерывается с ошибками вроде

undefined method `order' for #<Array:0x1887c2c>

или

undefined method `page' for #<Array:0x1887c2c>

потому что я использую упорядочивание и нумерацию страниц, и он больше не может упорядочить арены.

Есть какие-нибудь идеи, как получить все продукты в элементе ActiveRecord Relation в моем контроллере?спасибо

ОБНОВЛЕНИЕ

так, когда я использую следующее:

class Category < ActiveRecord::Base
    acts_as_nested_set

    attr_accessible :name, :description, :lft, :rgt, :parent_id   

    has_many :categorizations
    has_many :products, :through => :categorizations

    attr_accessor :product_list

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

    def all_products
       Product.find(:all, :conditions => { :category_id => branch_ids } )
    end


end

и спрашиваю у контроллера @category.all_products я получаю следующую ошибку:

Mysql::Error: Unknown column 'products.category_id' in 'where clause': SELECT `products`.* FROM `products` WHERE `products`.`category_id` IN (6, 8, 9)

Как получить все продукты с этим созвездием?

ОБНОВЛЕНИЕ 2

Хорошо, так что я собираюсь начать щедрость,

Если я попытаюсь:

def all_products Категоризация.find (: все,: условия => {: category_id => branch_ids}) end

Я получаю снова undefined methodorder 'for # `Мне нужно знать, как я могу получить все продукты отношения many_to_many как отношения ActiveRecord.

ОБНОВЛЕНИЕ 3

Я поставил соответствующий кодв сущности https://gist.github.com/1211231

Ответы [ 3 ]

5 голосов
/ 13 сентября 2011

Ключ с awesome_nested_set должен использовать диапазон в столбце lft .Вот пример кода того, как я делаю это с прямой связью (категория has_many статьи)

  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

Затем где-то в контроллере

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

, который найдет все статьи под категориями яблоки, апельсины, бананы и т. д. Вы должны адаптировать эту идею с помощью объединения по категориям (но вы уверены, что вам здесь нужны отношения многие ко многим?)

В любом случае, я бы попробовал это:

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

Дайте мне знать, если есть какие-то ошибки

3 голосов
/ 07 сентября 2011

Есть несколько способов улучшить ваш код, но если вы ищете все продукты, которые принадлежат к категории и потомкам (потомкам) этой категории, то почему вы не сделаете это так:

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

def all_products
  Product.find(:all, :conditions => { :category_id => branch_ids } )
end

Я сделал здесь некоторые предположения, но я надеюсь, что вы поняли идею.

0 голосов
/ 29 января 2014

Расширяя ответ charlysisto, когда вы имеете дело с has_and_belongs_to_many категориями, вы скоро обнаружите, что перспектива грубой силы довольно медленная ... Вам нужно какое-то "промежуточное ПО", чтобы сделать это быстрее ...

Ответ socjopata дает хороший подход к решению этой проблемы.Итак, вы используете определение

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

в вашем category.rb файле (модель).

Затем, например, в вашем контроллере (пример с разбиением на страницы):

@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)

Наконец, на ваш взгляд, вам понадобится небольшая "техника" для того, чтобы иметь нумерацию страниц.Вы будете разбивать на страницы @prodcats, а не @products ...

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

Этот подход намного быстрее, КОГДА ОБРАЩАЕТСЯ С many_to_many, но не на 100% политкорректнымДолжен признать.

...