2012-04-03 68 views
0

我想找到的标签与在一个参数数组通过标签的所有帖子。 帖子通过关联有很多标签。优化上的has_many选择查询:通过属性关联

目前我的代码如下所示:

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 

什么我基本上做的是找到根据参数数组实际的标签模型,将它们放入一个数组,然后我在所有运行一个选择查询搜索那些具有相同标签数组的帖子。

有更好的和更清洁的方式做到这一点?

回答

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 /模型/ post.rb

scope :with_tags, lambda { |tags| joins(:tags).group('posts.id').where(:tags => { :id => tags.map { |t| t.id } }).having("COUNT(*) = ?", tags.length) } 

UPDATE

下面介绍一下with_tags范围如下:

  1. joins(:tags)首先我们将tags表加入到posts表中。当您使用符号语法
  2. where(:tags => { :id => tags.map { |t| t.id } })我们想要的标签进行过滤,只找到提供这些标签Rails会用一个内部联接做。由于我们提供了一个标签对象列表,我们使用map来生成一个ID数组。然后使用该数组在where子句中创建WHERE field IN (list)查询 - 散列语法内的散列用于表示表中的表,然后表中的列。
  3. group('posts.id')所以,现在,我们有必要标签的职位名单,但是,如果有多个标签,我们将(对每个匹配的标签一次)多次列出的职位,所以我们组由posts.id使我们只为每个帖子返回1行(这也需要我们可以在步骤4中进行计数)
  4. having("count(*) = ?", tags.length)这是难题的最后一部分。现在我们已按帖子分组,我们可以计算与此帖子相关联的匹配标签数量。只要重复的标签是不然后允许,如果匹配的标签(count(*))的数量是一样的,我们用(tags.length)正在寻找那我们可以肯定的是,交了所有我们与正在寻找标签的标签数。

您可以找到有关通过阅读Active Record Query Interface Guide

+0

感谢供机型不同的查询方法有很多详细信息!这真的很有帮助。 你能解释一下范围说明,因为我也想了解发生了什么? 如何在RSPEC中测试该声明? – 2012-04-03 13:12:42

+0

嗨加尔,将扩大我的答案解释范围说明 – 2012-04-03 15:53:14

+0

感谢您的非常详细的答案! 我怎么Post.followed_by(@user)的所有标签? 帖子通过标签有很多标签 – 2012-04-08 11:32:41