icon
icon

Railsのincludesの書き方を現役エンジニアが解説【初心者向け】

初心者向けにRailsのincludesの書き方について現役エンジニアが解説しています。Railsのincludesを使うと、必要以上にSQL文が発行されるのを防ぐことが出来ます。書き方の例としては、includesメソッドの引数にあらかじめ読み込んで置きたいテーブルを指定したりします。

テックアカデミーマガジンは受講者数No.1のプログラミングスクール「テックアカデミー」が運営。初心者向けにプロが解説した記事を公開中。現役エンジニアの方はこちらをご覧ください。 ※ アンケートモニター提供元:GMOリサーチ株式会社 調査期間:2021年8月12日~8月16日  調査対象:2020年8月以降にプログラミングスクールを受講した18~80歳の男女1,000名  調査手法:インターネット調査

Railsのincludesの書き方について解説します。

 
そもそもRubyについてよく分からないという方は、Rubyとは何なのか解説した記事を読むとさらに理解が深まります。

なお本記事は、TechAcademyのオンラインブートキャンプRuby講座の内容をもとに紹介しています。

 

田島悠介

今回は、Rubyに関する内容だね!

大石ゆかり

どういう内容でしょうか?

田島悠介

Railsのincludesの書き方について詳しく説明していくね!

大石ゆかり

お願いします!

 

includesとは

Railsのincludesとは、モデルの情報取得時の性能低下を防ぐために、関連付けられているモデルをあらかじめ取得しておくことです。

Railsでは「User has many articles」のようにアソシエーション(関連付け)を行うことができます。記事の作成者をまとめて表示したいような時に、何も考えずに素直に書くと次のようになるかと思います。

 

# models/user.rb
class User < ApplicationRecord
  has_many :articles
end
# models/article.rb
class Article < ApplicationRecord
  belongs_to :user
end
# 記事作成者を表示するコード
articles = Article.all
articles.each do |article|
  puts article.user.name
end

 

このコードを実行すると、次のようにSQL文が記事数の分だけ発行されるのがわかります。

 

Article Load (0.3ms) SELECT articles.* FROM articles
User Load (0.2ms) SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
"taro"
User Load (0.3ms) SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
"taro"
User Load (0.2ms) SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
"taro"
User Load (0.2ms) SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
"taro"
User Load (0.3ms) SELECT users.* FROM users WHERE users.id = 3 LIMIT 1
"taro"

 

このことをN+1問題と呼びます。同じユーザーの情報を表示するだけなのに、毎回同じSQL文を発行するのは無駄が多いですね。そこで使えるのがincludesメソッドです。

includesの書き方

引数に、事前に読み込みをしておくモデル(カラム)をシンボルで指定します。

今回の例でいくとarticles = Article.includes(:user)のように書きます。

User has many articles, Category has many articles のように、複数モデルとアソシエーションしている場合には、 articles = Article.includes(:user, :category)のようにカンマ(,)区切りで指定できます。

Group has many users, User has many articlesのように、より深い階層構造の場合には、articles = Article.includes(user: :group)というように指定できます。

上の2つの例を同時に満たすような場合は、articles = Article.includes([user: :group], :category) のように、階層関係を表す部分を[](もしくは {})で囲むことで指定できます。

[PR] Rubyのプログラミングで挫折しない学習方法を動画で公開中

includesを他のメソッド(order等)と組み合わせて使う方法

事前にデータを読み込んだ上で、さらにユーザー名で並び替えしたいような場合にはorderと組み合わせることもできます。ただし、Article.includes(:user).order(name:DESC) のように指定すると、articles.nameでの並び替えを実行しようとします。

この場合は Article.includes(:user).order(“users.name DESC”) のように、対象テーブル名とカラム名を合わせて指定する必要があるので、注意しておきましょう

またwhereなどと組み合わせる場合には、referenecesメソッドを使う必要があります。Article.includes(:user).references(:users).where(“users.id > 3”) のように指定すると、users.idが3より大きいものへの絞り込みができます。

実際に書いてみよう

Article, Userのデータを用意できたら、以下のコードを実行してみましょう。

 

# 記事作成者を表示するコード(includes 版)
articles = Article.includes(:user)
articles.each do |article|
  puts article.user.name
end

 

以下の実行例を見ると、2行目で必要なuserテーブルのデータを事前に読み込んでいること、そのため記事ごとの作成者を出力するときにはSQL文が発行されていないことがわかりますね。

 

Article Load (0.6ms) SELECT articles.* FROM articles
User Load (0.5ms) SELECT users.* FROM users WHERE users.id = 3
"taro"
"taro"
"taro"
"taro"
"taro"

 

N+1 問題はRailsアプリケーションの表示速度に影響するので、includesで事前に必要なデータを読み込むようにすると表示が速くなるかもしれません。覚えておくと良いでしょう。

 

筆者プロフィール

メンター稲員さん

フリーランスエンジニア。
大手SEからフリーランスのWeb系エンジニアにジョブチェンジ。

経験言語:Ruby、Rails、Python、C/C++、Java、Perl、HTML/CSS3、JavaScript、CoffeeScript,Node.js。
おうち大好きマンです。

 

大石ゆかり

内容分かりやすくて良かったです!

田島悠介

ゆかりちゃんも分からないことがあったら質問してね!

大石ゆかり

分かりました。ありがとうございます!

 

TechAcademyでは、初心者でもRuby on Railsを使ったプログラミングを習得できるオンラインブートキャンプRuby講座を開催しています。

挫折しない学習方法を知れる説明動画や、現役エンジニアとのビデオ通話とチャットサポート、学習用カリキュラムを体験できる無料体験も実施しているので、ぜひ参加してみてください。