はじめに
この記事では、Railsで用いられる「アソシエーション機能」について
実務上のメリットや使いこなしポイントを紹介します。
この記事でわかること
- Railsのアソシエーション機能の基礎
- 直接操作とアソシエーション機能を使った操作の違い
- アソシエーション機能のメリット
- N + 1問題とネストJSON問題の解決
この記事の対象者
- Rails初心者/中級者
- モデル設計で迷う人
- N+1問題やeager_loadに関心がある人
- ネストJSONを書くのが面倒な人
動作環境・使用するツールや言語
- OS バージョン: macOS Sequoia 15.5
- ツール: VSCode 1.102.1
- 言語: Ruby 3.4.4
- フレームワーク: Rails 8.0.2
1. アソシエーション機能とは
アソシエーションとは、モデル(データベースのテーブル)同士を関連付ける機能です。
身近な例で言えば
| モデル | 概要 |
|---|---|
| User | ユーザー(Xアカウント)はたくさんのツイートを投稿できる |
| Tweet | ツイートは1人のユーザーに必ず紐づいている |
コード化すると以下のようになります。
class User < ApplicationRecord
has_many :tweets
end
class Tweet < ApplicationRecord
belongs_to :user
end
このように「モデル同士のつながり(=関係)」をコードで表すのがアソシエーションです。
Railsでは【has_many】や【belongs_to】以外にも、複数の関連付け方法が用意されています。
気になる方は、次の記事を参考にしてください。
https://qiita.com/aisaka1653/items/43b1843c401e50930ed2
https://zenn.dev/kspn/articles/fa6858f69385a4
2. アソシエーション機能のメリット
結論を言うと
アソシエーションを使うことで、モデル間のデータを直感的なコードで操作できます。
コードを用いて説明します。
概念図
userモデル
| id | name | created_at |
|---|---|---|
| 1 | ichiro | 2025-11-27 15:00:00 |
| 2 | hanako | 2025-11-27 17:00:00 |
| 3 | takashi | 2025-11-27 18:00:00 |
アソシエーション機能を使わない場合
# ユーザーの最初のレコード(ichiro)を取得(id = 1)
user1 = User.first
# 上から3番目のレコード(takashi)を取得(id = 3)
user2 = User.third
# user_idを明示的に指定して新しいツイートを作成
Tweet.create(content: "はじめてのツイート!", user_id: user1.id)
Tweet.create(content: "Hello World.", user_id: user2.id)
tweet = Tweet.find(1)
# 投稿者のユーザー情報を user_id で探す
user = User.find(tweet.user_id)
作成されたTweetレコード
| id | content | user_id | created_at |
|---|---|---|---|
| 1 | はじめてのツイート! | 1 | 2025-11-27 19:00:00 |
| 2 | Hello World. | 3 | 2025-11-27 20:00:00 |
このようにuser_idを直接設定する必要があります。
アソシエーション機能を使う場合
user1 = User.first
user2 = User.third
# ユーザーに新しいツイートを追加
user1.tweets.create(content: "はじめてのツイート!")
user2.tweets.create(content: "Hello world.")
# 既存のツイートの投稿者(ユーザー)を取得
tweet = Tweet.find(1)
tweet.user # このツイートを書いたユーザー情報が取得できる
作成されたTweetレコード
| id | content | user_id | created_at |
|---|---|---|---|
| 1 | はじめてのツイート! | 1 | 2025-11-27 19:00:00 |
| 2 | Hello World. | 3 | 2025-11-27 20:00:00 |
アソシエーションはuser.idを参照して、Tweetテーブルに「そのユーザーのid」を自動的に保存します。
※user_idカラムはマイグレーションファイルで事前に定義する必要あり。
(アソシエーション機能を使わない場合と同様)
アソシエーション機能のメリット
- オブジェクト指向的に関連を扱える(本章で解説)
(user.tweets, tweet.user のように自然なコードで関係を操作) - includes で一括ロードし、N+1問題を防ぎやすい
(複数データ取得時の効率化とパフォーマンス向上) - ネストJSON作成やForm設計が柔軟
(複雑なデータ構造も容易に表現可能) - 結果的に保守性・拡張性が高まる
(コードや設計が分かりやすく、改修にも強い)
本章では1の「オブジェクト指向的に関連を扱える」について解説しました。
次章では2のN+1問題と3のネストJSONについて解説します。
3. includesメソッド でN+1問題を解決
N + 1問題とは
例えば「全ユーザーと各ユーザーのツイート一覧」を表示したい場合…
何も対策しないと以下のコードになります。
users = User.all
users.each do |user|
# userの数だけtweetテーブルを参照する
user.tweets.each do |tweet|
puts "#{user.name}: #{tweet.content}"
end
end
Userを全部取得(1回のSQL)した後、各Userごとに tweets を取得します(Userが100人なら100回SQL実行)。
「N+1件」SQLが発行されて、レスポンスタイムが悪化します。
ユーザー体験が損なわれますよね?
includes で一括ロード
users = User.includes(:tweets)
users.each do |user|
# tweetテーブルは参照しない
user.tweets.each do |tweet|
puts "#{user.name}: #{tweet.content}"
end
end
includes は「アソシエーションが定義されているモデル」に対して使える “Eager Loading” 機能です。
【user.includes】で、tweets分もまとめてSQLで取得します。
以降、user.tweetsを呼んでもSQLが追加で発行されません。
効率良くDBアクセスできてページ表示が高速になるので、積極的に使っていくべきでしょう。
includesメソッドはRailsが必要に応じて、【preload】か【eager_load】のいずれかでSQLを発行するそうです。
【includes】【preload】【eager_load】の使い分けについては長くなるので説明を省略させていただきます。
詳しく知りたい方は以下の記事を参考にしてください。
https://zenn.dev/mithuami/articles/c4b0e9694182d1
https://qiita.com/massaaaaan/items/4eb770f20e636f7a1361
4. ネストJSONを回避
APIの出力結果「ユーザー情報+そのユーザーのツイート一覧」を1つのJSONでフロントに返したいとき…
アソシエーションがあると、以下のように書けます。
users = User.includes(:tweets)
users.as_json(include: :tweets)
# 以下のコードが必要なくなる
# {
# [
# { id:1, name:"ichiro",
# tweets:
# [
# {id:1, content:"..."},
# ...
# ]
# },
# ...
# ]
# }
親子関係のデータ構造(ユーザーとそのツイート)が簡単に表現できます。
また「1つのフォームでユーザー情報+複数ツイートをまとめて登録・編集」したい場合は、
accepts_nested_attributes_for を使って、userとtweetsをまとめて管理できます。
class User < ApplicationRecord
has_many :tweets
accepts_nested_attributes_for :tweets
end
fields_forヘルパーを活用することで、親(User)+子(Tweet)をまとめて操作・登録・バリデーションできます。
詳しくは、以下の記事を参考にしてみてください。
https://qiita.com/kazyam/items/4fd10396532c254d21b1
まとめ
この記事では、Railsのアソシエーション機能によるモデル間の関係管理の基礎と、実務で役立つメリット・ポイントを解説しました。
Railsのアソシエーションは、「データ設計」と「コード設計」の両方をスマートにしてくれる神機能です。
大規模開発やAPI構築でも、まずは関連付けの設計から始めてみましょう!