支持我有多个项目和类别的模型,采用多对多关系
class Item < ActiveRecord::Base
has_and_belongs_to_many :categories
class Category < ActiveRecord::Base
has_and_belongs_to_many :items
现在我想过滤掉至少包含一个项目的类别,最好的方法是什么?
答案 0 :(得分:2)
我想回应@Delba的答案并对其进行扩展,因为它是正确的 - 如果您正确设置了索引,那么@huan的儿子建议使用count列是完全没必要的。
我想补充一点,你可能想使用.uniq,因为它是多对多你只想要DISTINCT类别回来:
Category.joins(:items).uniq
使用联接查询可以让您更轻松地将条件用于项目计数,从而提供更大的灵活性。例如,您可能不想计算enabled = 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
祝你好运,
斯图
答案 1 :(得分:1)
Category.joins(:items)
此处有更多详情:http://guides.rubyonrails.org/active_record_querying.html#joining-tables
答案 2 :(得分:0)
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"
。
答案 3 :(得分:0)
请注意,其他人的回答是不是很好!
性能最佳的解决方案:
最好使用 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”关系你刚才写的
belongs_to :parent, :counter_cache=>true
并且在parent_model中有一个字段items_count(items是复数化的has_many类名)
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
在has_and_belongs_to_many关系中你必须像上面那样把它写成你自己的