我想找到所有标记有在params数组中传递的标记的帖子。 帖子通过关联有很多标签。
目前我的代码如下:
if params.has_key?(:tags)
params[:tags].each do |tag|
@tags = Array.new if @tags.nil?
@tag = Tag.find_by_content(tag)
@tags << @tag if @tag
end
@allposts = Post.followed_by(@user).select { |p| p.tags.size != 0 && (p.tags & @tags).size == p.tags.size }
else
@allposts = Post.followed_by(@user)
end
我基本上做的是根据params数组找到实际的标签模型并将它们放入一个数组中,然后在所有帖子上运行一个select查询来搜索那些具有相同标签数组的帖子。
有更好更清洁的方法吗?
答案 0 :(得分:1)
您可以将Tag.find
查询转换为对数据库的单个请求,并添加适当的where子句以限制返回的帖子:
finder = Post.followed_by(@user)
if params.has_key?(:tags)
@tags = Tag.where(:content => params[:tags])
finder = finder.with_tags(@tags)
end
@allposts = finder.all
app / models / post.rb 中的
<强>更新强> 这是with_tags范围的作用:scope :with_tags, lambda { |tags| joins(:tags).group('posts.id').where(:tags => { :id => tags.map { |t| t.id } } ).having("COUNT(*) = ?", tags.length) }
joins(:tags)
首先,我们将标签表加入posts表。当您使用符号语法where(:tags => { :id => tags.map { |t| t.id } } )
我们希望过滤标记,以便只查找提供的标记。由于我们提供了标记对象列表,因此我们使用map生成ID数组。然后在where子句中使用此数组来创建WHERE field IN (list)
查询 - 哈希语法中的哈希用于表示表,然后表示表中的列。 group('posts.id')
现在我们有一个包含必要标签的帖子列表,但是,如果有多个标签我们会多次列出帖子(每个匹配标签一次),所以我们按帖子分组.id这样我们每个帖子只返回1行(我们也可以在步骤4中进行计数)having("count(*) = ?", tags.length)
这是拼图的最后一部分。现在我们已按照帖子进行分组,我们可以计算与此帖子相关联的匹配标签的数量。只要不允许重复标记,那么匹配标记的数量(count(*)
)是否与我们搜索的标记数量相同(tags.length
)那么我们可以确定帖子有我们正在搜索的所有标签。