0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails初学者】テーブル設計とアソシエーションの関係を整理してみた

0
Posted at

はじめに

Railsの学習でテーブル設計に取り組んでいたところ、「アソシエーション」という言葉が出てきました。最初は「テーブル設計とモデルの関連付けって何が違うの?」と混乱したので、アウトプットも兼ねて自分の理解を整理します。

初学者の理解なので、間違いがあればコメントで教えていただけると嬉しいです。

この記事で書くこと

  • テーブル設計(ER図)とマイグレーションの関係
  • アソシエーションとは何か
  • belongs_to / has_many / has_one の違い
  • 外部キーとの関係
  • users / boards / comments の関係

テーブル設計は「設計図を描く作業」

最初に混乱したのが、「テーブル設計って、db/migrate の中身を自分で書くことと同じ?」という点でした。

整理すると、次の流れになります。

① どんな情報を保存する必要があるか考える
   ↓
② テーブル名・カラム名・型・関連を決める(ER図を描く)
   ↓
③ その設計を元にマイグレーションファイルを作成する
   ↓
④ rails db:migrate を実行してテーブルが作られる

テーブル設計(ER図)は、マイグレーションファイルを書く前の設計図です。設計を飛ばしていきなり実装すると、次のような手戻りが起きやすくなります。

  • 「このカラムの型、文字列でよかったっけ?」
  • 「外部キーを入れ忘れてた」
  • 「あとからカラムを追加しないといけない」

紙やdraw.ioなどで先に整理しておくと、実装がスムーズになるようです。

アソシエーションとは

アソシエーションとは、Railsのモデル同士の**「関連付け」**を表す仕組みです。

たとえば、ユーザーが複数の投稿(Board)を持つ場合、「ユーザーと投稿は関連している」という情報をモデルに定義できます。

アソシエーションがない場合

@user = User.find(1)
@boards = Board.where(user_id: @user.id)  # 毎回条件を自分で書く必要がある

アソシエーションがある場合

@user = User.find(1)
@boards = @user.boards  # 関連データをすぐ取得できる

関連データの取得や操作がシンプルに書けるのが、アソシエーションの便利なところです。

主な3つの関連付け

関連付け 説明 具体例
belongs_to あるモデルが他のモデルに「従属」する 投稿(Board)はユーザー(User)に属する
has_many あるモデルが複数の他モデルを「持つ」 ユーザーは複数の投稿を持つ
has_one あるモデルが1つの他モデルを「持つ」 ユーザーは1つのプロフィールを持つ

has_one の例として、プロフィール情報を別テーブルに分ける場合はこう書きます。

# Userモデル
class User < ApplicationRecord
  has_one :profile
end

# Profileモデル
class Profile < ApplicationRecord
  belongs_to :user
end

こう定義すると user.profile でプロフィールを取得できます。

どっちに何を書くか迷ったら

最初は「どっちに has_many、どっちに belongs_to を書くんだっけ?」と迷いました。次のように覚えると整理しやすかったです。

1対多の「多」側に belongs_to を書く

外部キーとの関係

アソシエーションを使うには、通常 belongs_to 側のテーブルに外部キー(例: user_id)のカラムが必要です。

テーブル設計の段階で「どのテーブルが誰に属するか」を考えておくことが、そのままアソシエーションの設計につながります。ここで設計とモデルの関連付けがつながりました。

マイグレーションでは references を使うと、外部キーのカラムをまとめて作れます。

class CreateBoards < ActiveRecord::Migration[7.1]
  def change
    create_table :boards do |t|
      t.string :title, null: false
      t.text :body, null: false
      t.references :user, null: false, foreign_key: true

      t.timestamps
    end
  end
end

t.references :user で user_id カラムが作られ、foreign_key: true で外部キー制約も付きます。

「誰が親で、誰が子か」を考える

  • users と boards:1人のユーザーが複数の投稿をするので、users が親、boards が子
  • boards と comments:1つの投稿に複数のコメントがつくので、boards が親、comments が子
  • users と comments:1人のユーザーが複数のコメントをするので、users が親、comments が子

comments テーブルには user_id と board_id の2つの外部キーが必要になります。「誰が」「どの投稿に」コメントしたのかを両方記録する必要があるからです。

class CreateComments < ActiveRecord::Migration[7.1]
  def change
    create_table :comments do |t|
      t.text :body, null: false
      t.references :user, null: false, foreign_key: true
      t.references :board, null: false, foreign_key: true

      t.timestamps
    end
  end
end

dependent: :destroy について

親を削除したときに、子のデータも一緒に削除する指定です。たとえばユーザーを削除したとき、そのユーザーの投稿やコメントが残ってしまうのを防げます。

開発の進め方についての理解

「最低限の機能から作って、あとから足していく」という進め方についても整理しました。

  1. アプリ全体で必要なテーブルを考えて、ER図を描く
  2. 実装の優先順位を決める(ユーザー登録・ログインができないと他の機能が作れない)
  3. 優先度の高い機能から実装 → 動作確認 → デプロイ
  4. 残りの機能(投稿、コメント、いいねなど)を段階的に追加する

つまり「全体のER図は先に考えておくけど、実装は優先度順に進める」というイメージです。全体像が見えていないと、あとから「このテーブルも必要だった」と大きな手戻りになりやすいので、最初に全体を見渡しておくことが大事なんだと理解しました。

まとめ

  • テーブル設計(ER図)は、マイグレーションを書く前の設計図
  • アソシエーションは、モデル同士の関連付けで、関連データの取得が簡単になる
  • belongs_to 側のテーブルには外部キー(user_id など)が必要
  • 「1対多の『多』側に belongs_to」と覚えると迷いにくい
  • 全体のER図を先に描き、実装は優先度順に進める

テーブル設計の段階で「どのテーブルが誰に属するか」を考えておくことが、そのままアソシエーションの理解につながると実感しました。

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?