2012-04-03 71 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