簡體   English   中英

Rails3 ActiveRecord-獲取所有具有A和B的記錄(通過has_many關系)

[英]Rails3 ActiveRecord - Fetching all records that have A and B (through a has_many relationship)

我具有以下模型關系:

class Article < ActiveRecord::Base
    has_many :tags, :through => :article_tags
end
class ArticleTag < ActiveRecord::Base
    belongs_to :tag
    belongs_to :article
end
class Tag < ActiveRecord::Base
    has_many :articles, :through => :article_tags
end

現在,我想加載所有標記為“ A”和“ B”的文章。

我對Rails還是很陌生,距離我從事任何認真的web-dev / SQL工作已經有幾年了,但是對於我一生來說,我一直無法弄清楚如何構造一個ActiveRecord查詢來執行此操作。

在本機SQL中執行此操作的一種方法如下:

    SELECT a.* FROM articles a
INNER JOIN article_tags at ON at.article_id = a.id
INNER JOIN tags t ON at.tag_id = t.id
     WHERE t.name = 'A'

intersect 

    SELECT a.* from articles a
INNER JOIN article_tags at ON at.article_id = a.id
INNER JOIN tags t ON at.tag_id = t.id
     WHERE t.name = 'B'

現在,這可能不是最有效的SQL,但是它可以工作。 在這很晚的時候,我想不出更好的SQL解決方案。

更新:進一步的調查使我了解了此SQL:

  SELECT a.* FROM article_tags at, articles a, tags t 
   WHERE at.tag_id = t.id 
     AND (t.name = 'A' OR t.name = 'B') 
     AND a.id = at.vehicle_id 
GROUP BY a.id HAVING COUNT(a.id) = 2

這似乎更簡單(不太冗長),但效率卻更高。 但是,我可能可以更輕松地使用此SQL構造“ find_by_sql” ActiveRecord查詢。

任何有關如何最好地使用ActiveRecord進行此類查詢(最好不訴諸SQL)的指南,將不勝感激。

我最終解決了自己的問題。 我構造了一個命名范圍,如下所示:

scope :tagged, lambda { |tag, *tags|
    tags = tags.unshift(*tag)
    joins(:tags).
        where("lower(tags.name) = '" + tags.uniq.collect{ |t| t.to_s.downcase }.join("' OR lower(tags.name) = '") + "'").
        group("articles.id").
        having("count(articles.id) = #{tags.count}")
}

因此,現在我可以在控制器中執行此操作:

@tagged_articles = Article.tagged('A', 'B', 'C')

@tagged_articles將包括所有標記為“ A”,“ B”和“ C”的所有文章。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM