![](/img/trans.png)
[英]Rails 4 has_many associations w/Postgres: query table A for all records that actually have B, C, and D
[英]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.