如何查找记录,其has_many通过对象包括某些列表的所有对象?

我有一个典型的标签和任何对象关系:说

class Tag  :tagazations end class Tagazation  { :scope => :project_id } end class Project  :tagazations end 

这里没什么特别的:每个项目都有一个或多个标签。
该应用程序具有搜索function:您可以选择某些标签,我的应用程序应该显示所有标记有所有提及标签的项目。 所以我得到了一个必要的tag_ids数组,然后遇到了这么简单的问题

要在一个查询中执行此操作,您需要利用常见的double not exists SQL查询,它基本上为所有Y找到X.

在您的实例中,您可能会这样做:

 class Project < ActiveRecord::Base def with_tags(tag_ids) where("NOT EXISTS (SELECT * FROM tags WHERE NOT EXISTS (SELECT * FROM tagazations WHERE tagazations.tag_id = tags.id AND tagazations.project_id = projects.id) AND tags.id IN (?))", tag_ids) end end 

或者,您可以使用count,group和having,虽然我怀疑第一个版本更快但可以随意进行基准测试:

 def with_tags(tag_ids) joins(:tags).select('projects.*, count(tags.id) as tag_count') .where(tags: { id: tag_ids }).group('projects.id') .having('tag_count = ?', tag_ids.size) end 

这将是一种方法,虽然绝不是最有效的方法:

 class Project < ActiveRecord::Base has_many :tagazations has_many :tags, :through => :tagazations def find_with_all_tags(tag_names) # First find the tags and join with their respective projects matching_tags = Tag.includes(:projects).where(:name => tag_names) # Find the intersection of these lists, using the ruby array intersection operator & matching_tags.reduce([]) {|result, tag| result & tag.projects} end end 

那里可能有一些拼写错误,但你明白了