получите все товары категорий и дочерних категорий (rails, awesome nested set)
имея электронной коммерции приложение в стадии разработки, я пытаюсь получить мою голову вокруг следующих проблем: У меня есть мои категории, реализованные через плагин 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
строка I commented out-вспомогательный метод, который я написал сам в модели категорий, которая возвращает все продукты категории и ее дочерние категории в массиве.
определяется следующим образом:
# 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>
потому что я использую порядок и разбиение на страницы, и он больше не может заказать arary.
любой идеи как получить все продукты в элементе отношения ActiveRecord в моем контроллере? спасибо
обновление
Итак, когда я использую следующий:
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 (: all,: conditions = > {: category_id => branch_ids } ) конец
Я вам еще раз undefined method
заказ для #`
Мне нужно знать, как я могу получить все продукты отношения many_to_many как отношение ActiveRecord.
обновление 3
Я поместил соответствующий код в суть https://gist.github.com/1211231
3 ответов
ключ с 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)
это найдет все статьи в категориях яблоки, апельсины, бананы и т. д. Вы должны адаптировать эту идею с помощью join on categorizations (но вы уверены, что вам нужны отношения " многие ко многим здесь?)
В любом случае я бы попробовал это :
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
Дайте мне знать, если есть какие-либо gotcha
есть несколько способов улучшить свой код, но если вы ищете все продукты, которые принадлежат к категории и детям (потомкам) категории, то почему вы не будете делать это так:
def branch_ids
self_and_descendants.map(&:id).uniq
end
def all_products
Product.find(:all, :conditions => { :category_id => branch_ids } )
end
Я сделал некоторые предположения здесь, но я надеюсь, что вы поняли идею.
расширение ответа charlysisto, когда вы имеете дело с has_and_belongs_to_many
категории, вы скоро узнаете, что перспектива грубой силы довольно медленная... Вам нужно какое-то" промежуточное программное обеспечение", чтобы сделать его быстрее...
ответ socjopata дает хороший подход к тому, как улучшить это. Итак, вы используете определение
def branch_ids
self_and_descendants.map(&:id).uniq
end
в своем (модель).
тогда, например, в контроллере (например, с 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)
наконец, на ваш взгляд, вам понадобится небольшая "техника", чтобы иметь разбиение на страницы. Вы будете вставить на @prodcats
, а не @products
...
<%= will_paginate @prodcats %>
<% @products.each do |product| %>
....
<% end %>
этот подход намного быстрее, ПРИ РАБОТЕ С many_to_many
, хотя и не на 100% политкорректно, я должен признать.