Railsでアソシエーションされたモデルを条件にして検索する

ブログポストが複数カテゴリを持てるという場合で、
ある記事と同じカテゴリを持つ記事を探すということをやりたい。
 

Screen Shot 2014-02-23 at 9.34.23 AM
 

ruby
1
2
3
4
5
6
7
8
9
10
11
12
13
#Postモデル
class Post < ActiveRecord::Base
    has_and_belongs_to_many :categories
end

#交差テーブル
class CategoriesPost < ActiveRecord::Base
end

#Categoryモデル
class Category < ActiveRecord::Base
    has_and_belongs_to_many :posts
end

 

ruby
1
2
3
4
5
post = Post.first
categories = Category.joins(:posts).where("posts.id = ?", post.id).select("categories.id")
category_ids = categories.map { |c| c.id }.join(',')

posts = Post.joins(:categories).where("categories.id IN (#{category_ids})").uniq

 
これで取り出せはするんだけど、カテゴリは複数持てる設定だから、INでやると当然記事は重複する。id=1の記事はカテゴリ13,33,36を持っているからid=1の記事を3回も取得してしまう。

uniqで重複は消してしまえるけど、もっとスマートな方法ないかな。
SQLに詳しい人教えてください。


references(*args)という便利なメソッドを@naotorさんから教えて頂きましたー。
Categoryのidは自分で集めなくてもpost.category_idsでいけるんですね。
いつかRailsチュートリアルで見た気がするな。

http://api.rubyonrails.orgから引用

ruby
1
2
3
4
5
6
7
User.includes(:posts).where("posts.name = 'foo'")
# => Doesn't JOIN the posts table, resulting in an error.

User.includes(:posts).where("posts.name = 'foo'").references(:posts)
# => Query now knows the string references posts, so adds a JOIN

ruby
1
2
post = Post.first
posts = Post.includes(:categories).where(categories_posts: {category_id: post.category_ids}).references(:categories)

何かありましたらコメントをどうぞ

comments powered by Disqus

人気の記事

950 Points チリ出身のギタリストが弾くドラゴンボールZがむちゃくちゃかっこいい…
774 Points Wordpress + Heroku + PostgreSQL + Amazon S3 = ¥0 / 無料でサイト運営
700 Points Rubyのチートシート 変数 / クラス / モジュール
524 Points Rubyのチートシート / アクティブサポート
451 Points 紙のデザイナーがウェブ開発できるようになるまでに必要なこと
435 Points Rails / Google Analyticsのデータを使って分析や管理画面のためのグラフをつくる
323 Points RailsとHerokuでノーティフィケーションをプッシュする / PusherとTurbolinksの兼ね合い
222 Points Rails / RSpec テスト書いたことない メンドクサイ(n´Д`)という時のチートシート
193 Points Rails / Ajaxを使って画面遷移しない一時保存機能をつける
193 Points Protractorでスクレイピングしてみた