Railsのjoinsで3つのテーブルをくっつける

エンジニアの皆さん、こんにちは!
そうでない方も、読んでいただきありがとうございます!!

今日の話はRailsのjoinsメソッドです。
3つのテーブルをくっつける場合に、どうくっつくかで2つの書き方あるんだ~と思ったので、それを解説していきます!

Railsのjoinsメソッドとは

公式リファレンスは以下になります。
http://railsdoc.com/references/joins
joinsメソッドを使うことで、INNER JOINを使ったSQL文が発行できるということですね。

2つのテーブルをくっつける

まずは簡単に2つのテーブルをくっつける場合で考えてみます。
上記のリファレンスにあるように、2つのテーブルをくっつける場合は、以下のように書きます。

Category.joins(:articles)

このように書くときのテーブルは以下のような関係になっています。

Articleテーブルがcategory_idみたいなのを持っているので、くっつけられます。
発行されるSQL文は以下の通りです。

SELECT * FROM categories
INNER JOIN articles
ON articles.category_id = categories.id

3つのテーブルでのJOIN

では冒頭でも書いたように、3つのテーブルでのJOINを考えてみます。
パターンが2つあるので分けて考えてみましょう。

前提としてこの上記リンク先にある、この状態です。

パターン① 親に2つとも結合関係がある場合

上記の図でいうと、Articleに対してCategoryとTagがくっついている状態のことです。
これらのJOINは以下のように書けます。

Article.joins(:category, :comments)

ArticleにCategoryがくっつくこともできますし、Commentもくっつくことができます。
アソシエーションが単一なのか複数なのかによって、テーブル名を書くときに単数か複数かが変わるということですね。
発行されるSQL文は以下のようになります。

SELECT * FROM articles
INNER JOIN categories
ON articles.category_id = categories.id
INNER JOIN comments
ON articles.id = comments.articles_id

パターン② 1つずつ横にくっついていく場合

上記の図でいうと、Articleに対してCommentがくっついていて、Commentに対してGuestがくっついている状態のことです。
これらのJOINは以下のように書けます。

Article.joins(comments: :guest)

ArticleにCommentがくっついて、そこにGuestがくっつくという関係ですね。
発行されるSQL文は以下のようになります。

SELECT * FROM articles
INNER JOIN comments
ON articles.id = comments.article_id
INNER JOIN guests
ON comments.id = guests.comment_id

この場合、くっつける順番が大事ですね。ArticleにGuestは直接くっつかないので、まずCommentをくっつける必要があります。

ちなみに。。。

上記のクエリは全てINNER JOINで発行されているので、どこかでJOINする相手がいなくなると、そのレコードは結果として返ってきません。

というのがINNER JOINで、LEFT OUTER JOINとの大きな違いなのですが、ここらへんの話はまた別途書きたいなと思います。

最後に

この記事、2か月くらい前に出したいなと思って書き途中でした。。。
やっと書き終えられて良かったです。
Railsはアソシエーションを正しく貼らないと、思ったクエリが発行できないのは、ちょっと難しいところだなと思います。
ただ、関係性を正しく理解できれば、アソシエーションの貼り方も迷わないのかなと思いました。
皆さん、RailsGuide読んで一緒に勉強しましょう!!