ActiveRecord найти категории, которые содержат хотя бы один элемент - PullRequest
1 голос
/ 22 ноября 2011

Поддержка У меня есть две модели для предметов и категорий, в отношении многих ко многим

class Item < ActiveRecord::Base
  has_and_belongs_to_many :categories 

class Category < ActiveRecord::Base
  has_and_belongs_to_many :items

Теперь я хочу отфильтровать категории, которые содержат хотя бы один элемент, как лучше всего это сделать?

Ответы [ 4 ]

2 голосов
/ 27 февраля 2012

Я бы хотел повторить ответ @ Delba и расширить его, потому что он правильный - то, что @huan son предлагает в столбце count, совершенно не нужно, если ваши индексы настроены правильно.

Я бы добавил, что вы, вероятно, хотите использовать .uniq, так как вы хотите, чтобы возвращались только категории DISTINCT:

Category.joins(:items).uniq

Использование запроса на объединение позволит вам более легко работать с количеством элементов, что обеспечивает большую гибкость. Например, вы можете не захотеть считать элементы, где включено = false:

Category.joins(:items).where(:items => { :enabled => true  }).uniq

Это сгенерирует следующий SQL-запрос, используя очень быстрые внутренние объединения:

SELECT `categories`.* FROM `categories` INNER JOIN `categories_items` ON `categories_items`.`category_id` = `categories`.`id` INNER JOIN `items` ON `items`.`id` = `categories_items`.`item_id` WHERE `items`.`enabled` = 1

Удачи, Stu

1 голос
/ 22 ноября 2011
Category.joins(:items)

Подробнее здесь: http://guides.rubyonrails.org/active_record_querying.html#joining-tables

0 голосов
/ 22 ноября 2011

пожалуйста, обратите внимание, что другие парни ответили НЕ производительно!

самое эффективное решение:

лучше работать с counter_cache и сохраните items_count в модели!

scope :with_items, where("items_count > 0")


has_and_belongs_to_many :categories, :after_add=>:update_count, :after_remove=>:update_count

def update_count(category)
  category.items_count = category.items.count
  category.save
end

для нормального отношения "владение_то" вы просто пишете

belongs_to :parent, :counter_cache=>true

, а в родительской модели у вас есть поле items_count(items - это имя класса во множественном числе has_many)

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

в отношении has_and_belongs_to_many вы должны написать его как свое собственное, как указано выше

0 голосов
/ 22 ноября 2011
scope :has_item, where("#{table_name}.id IN (SELECT categories_items.category_id FROM categories_items")

Это вернет все категории, у которых есть запись в соединительной таблице, потому что, якобы, у категории не должно быть записи, если у нее нет элемента. Вы можете добавить AND categories_items.item_id IS NOT NULL к условию выбора, просто чтобы быть уверенным.

Если вы не знаете, table_name - это метод, который возвращает имя таблицы класса ActiveRecord, вызывающего его. В этом случае это будет "categories".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...