2020-04-11
【Rails】ActiveRecordでJOIN先のテーブルのカラムで絞り込む
#includes や #joins でテーブルをJOINしたときに、軸となるテーブルではなくJOIN先のテーブルのカラムで絞り込む方法について。
例として、デッキとカードという2つのモデルがありデッキがカードをN個持つ関係にあるとする。
app/models/deck.rb
class Deck < ApplicationRecord
has_many :cards
endapp/models/card.rb
class Card < ApplicationRecord
belongs_to :deck
end※ 検証環境は以下の通り
- rails 6.0.1
- ruby 2.6.5
joins × merge
#joins と #merge を組み合わせる。#includes の場合は使えない。
Deck.joins(:cards).merge(Card.where(id: 1))
# => SELECT "decks".* FROM "decks" INNER JOIN "cards" ON "cards"."deck_id" = "decks"."id" WHERE "cards"."id" = $1 [["id", 1]]whereメソッドにテーブル名をkeyとして渡す
#joins の場合はINNER JOINとなり、#includes の場合はLEFT OUTER JOINになる。
Deck.joins(:cards).where(cards: { id: 1 })
# => SELECT "decks".* FROM "decks" INNER JOIN "cards" ON "cards"."deck_id" = "decks"."id" WHERE "cards"."id" = $1 [["id", 1]]
Deck.includes(:cards).where(cards: { id: 1 })
# => SELECT "decks"."id" AS t0_r0, ...(省略) FROM "decks" LEFT OUTER JOIN "cards" ON "cards"."deck_id" = "decks"."id" WHERE "cards"."id" = $1 [["id", 1]]文字列でJOIN先のテーブルを指定する
Deck.joins(:cards).where('cards.id = ?', 1)
# => SELECT "decks".* FROM "decks" INNER JOIN "cards" ON "cards"."deck_id" = "decks"."id" WHERE (cards.id = 1)#includes でこの書き方をする場合は #references と組み合わせないと動かない
Deck.includes(:cards).where('cards.id = ?', 1).references(:cards)
# => SELECT "decks"."id" AS t0_r0, ...(省略) FROM "decks" LEFT OUTER JOIN "cards" ON "cards"."deck_id" = "decks"."id" WHERE (cards.id = 1)
h3pei
フリーランスのソフトウェアエンジニア。Ruby / Rails アプリケーションの開発が得意領域。設計・実装・運用まで含めてプロダクト開発が好きです。
Questalという目標達成コミュニティサービスを開発しました。仲間と一緒に目標達成に取り組みたい方はぜひご利用ください。
<< 前の記事AWSアカウントとIAMユーザ
次の記事 >>git resetをちゃんと理解する