RailsでModelを使ってデーターベースのテーブル操作を行う際、別テーブルと結合してデータを取得したい場面もあります。そんなときは、joinsメソッドが便利です。本記事では、Railsのjoinsメソッドの使い方を、サンプルコードを交えてご紹介します。
Ruby on Railsのjoinsメソッドとは
Ruby on Rails(以下、Railsと記載)で使用するjoinsとは、テーブル同士を内部結合してデータ検索するためのメソッドです。SQL文の中でJOINを使って結合するのと同じ効果があります。
内部結合とは、各テーブル同士を関連付け結合キーとなるidが一致したデータのみを取得する結合方法です。idが一致しないデータは切り捨てられます。結合の種類には内部結合のほかに、外部結合もあります。
includesメソッドとの違い
Railsには、joinsと似たメソッドとしてincludesメソッドがあります。Modelの関連付けを行う際は、joinsを使うかincludesを使うか、迷うこともあります。
includesはデータの先読みをしてくれるメソッドとも言われています。includesメソッドを使用すると、関連するテーブルすべてのデータをまとめて取得してくれるので、参照先が多い場合には、効率の良い記述となります。
includesを使ったコード記述例
【基本構文】
モデル.includes(条件)
【コード記述例】
Book.includes(:categories)
【実行内容】
SELECT "books".* FROM "books"
SELECT "categories".* FROM "categories" WHERE "categories"."id" IN (1)
【取得内容】
includsメソッドを使うModel(Book)のテーブル(books)からすべてのデータを取得する
includesの引数として指定されたcategoriesテーブルから先に取得したbooksテーブルのidと合致するデータのみを取得する
Ruby on Railsのjoinsメソッドの使い方
Railsにおけるjoinsの使い方を、サンプルコードを交えながら見ていきましょう。まず、joinsの基本構文は以下のように記述します。
【基本構文】
Model名.joins(条件)
Model名には、joinsを使って内部結合のデータを取得する元となるテーブルへの接続Model名を指定します。「条件」には、Model名で指定したテーブルと関連付けたいテーブル名を指定します。
データベースの例
joinsを使ことで、どのようにデータが取得できるか、理解しやすいように、以下のデータベースにサンプルデータがあると仮定して進めていきます。
BookモデルとCategoryモデルがあります。これらのモデルはそれぞれbooks、categoriesというテーブルを操作するためのモデルです。booksテーブルにはcategoriesテーブルを参照するための外部キーが存在します。
テーブル名 | カラム名 |
---|---|
books | id book_name category_id author_id publishedmonth |
categories | id category_name |
joinsの使用例
これらのテーブルに対し、joinsを基本構文のまま使うと、実際には以下のようなSQL文としてテーブルに問い合わせが発行されます。
【コード記述例】
Category.joins(:books)
【発行されるSQL文】
SELECT categories.* FROM categories INNER JOIN books ON books.category_id = categories.id
結合したテーブルの値を取得する方法
joinsメソッドを基本構文で使用した場合の発行されるSQL文を確認してみましょう。SELECTでは、メソッドを使うModelのテーブルカラムしか取得していない(SELECT categories.*)ことに気付くでしょう。joinsの引数で指定するテーブルからの値は取得できていません。
結合を指定したテーブルのデータも取得するためには、以下のように記述し、scopeを作成する必要があります。
scopeを使ったコード記述例
【コード記述例】
scope :joins_get_all_columns, ->(*tables) {
joins(*tables).select("*")
}
Category.joins_get_all_columns(:books)
【発行されるSQL文】
SELECT * FROM "categories" INNER JOIN "books" ON "books"."categories_id" = "categories"."id"
検索条件を設定する方法
テーブルを結合し、キーが一致したデータだけを取り出すのではなく、さらに取得条件を設定したい場合は、joinsとwhere句を組み合わせます。joinsで内部結合した後にwhere句で条件を指定してデータ取り出せます。
【コード記述例】
Category.joins(:books).where(books: { publishedmonth: 8 })
joinsにて外部結合を実現する方法
Railsのjoinsメソッドは、内部結合を扱うメソッドです。それでは、外部結合を扱いたいときは、どのようなメソッドを使って記述すれば良いのでしょう。
Railsでは、SQL文の外部結合用の結合句を記述することで、外部結合を実行することができます。この記述は、利用するRailsのバージョンによって記述が異なるので、自分が使っているRailsのバージョンを確認したうえで実装しましょう。
外部結合とは?
外部結合とは、結合するテーブルに一致するキーが存在しなくても、データを取得する結合方式です。2つあるテーブルのどちらのテーブルを優先させるかによって、左外部結合と右外部結合があります。
左外部結合では、「LEFT OUTER JOIN」を使います。先にテーブル名を記述したテーブルが優先テーブルになります。右外部結合では、「RIGHT OUTER JOIN」を使います。多くの場合、左外部結合が使われます。
rails4以前で外部結合をする方法
Rails4以前のバージョンであれば、joinsメソッドを使って外部結合を実行します。joinsは内部結合のメソッドですが、引数に外部結合の結合句を直接記述することができます。
【コード記述例】
Category.joins("LEFT OUTER JOIN books ON categories.id = books.category_id")
rail5にて追加された新たな方法について
Rails5からは、left_outer_joinsというメソッドが追加されました。joinsを使わなくても、左外部結合専用のメソッドとして利用ができます。使っているRailsのバージョンがRails5以降の場合は、以下のコード記述を試してみましょう。
【コード記述例】
Category.left_outer_joins(:books)
Rails5でもjoinsメソッドは使える
Rails5以降も、joinsメソッドの引数に外部結合句を記述することもできます。Rails4以前のバージョンから5にバージョンアップした場合など、使い慣れたjoinsメソッドを使い続けていても、プログラムとしては問題ありません。
しかし、Rails5で専用のメソッドが用意され、効率的にプログラミングできるよう改善されているポイントといえるので、新しいメソッドに変えていくことをおすすめします。
Railsで複数テーブルの情報を取得してみよう!
本記事では、2つのテーブルを結合して情報を取得する方法としてjoinsメソッドを中心に解説しました。joinsの使い方には、まだまだ奥深いものがあり、ご紹介した以上に複雑な使い方も可能です。
まずは、joinsの基本的な使い方を覚え、テーブルの関係とどのようなデータが取得できるか確認し、習得しましょう。Modelの扱いに慣れてきたら、joinsの複雑な使い方やincludesなども使ってみましょう。