はじめに
Rails チュートリアルなどで、Railsの勉強をしていて、Twitterでいう、ツイート機能を作成する際、UserモデルやTweetモデルなどのマイグレーションファイルの作成をしていた時に、UserモデルとTweetモデルを関連させたいモデルがあった時などに使う、外部キーのカラムの追加に関して調べていたら勉強になったので、まとめておきます。
環境
この記事では以下の環境(2018年6月19日時点)で動作確認できました。
- Ruby: 2.4.1
- Rails: 5.0.7
前提
お題「お気に入り機能を作成したい」と思った時、現状、ユーザー情報があるusers
テーブルと、tweetのようなデータを扱うmicroposts
テーブルを関連づけて、お気に入り機能を作りたいと思ったとを仮定します。
テーブル名同士の関係としては、お気に入り機能なので、users : microposts = 多 : 多
の関係にしたいとします。モデル同士が多対多の関係になる場合には、中間テーブルを設置するのが有効な方法です。
中間テーブルとは
中間テーブルとは、users
やmicroposts
の関係を接続するテーブルです。例えば、User
が特定のMicropost
をお気に入りする場合、users
テーブルの id とmicroposts
テーブルのidを接続するテーブルを作成します。その接続するテーブル(例:likes
テーブル)にはuser_id
とmicropost_id
を設置します。 そのテーブルのレコードにuser_id
が1で、micropost_id
が2のものがあったとすると、idが 1のUser
がidが10のMicropost
を好き、ということを意味します。
そんな関係の中間テーブルを作るために、まず、reference型を使ってモデルを作成していきましょう。
モデル作成
users : microposts = 多 : 多
の関係になるような中間テーブルである(Like
モデル)を作りたいとします。
$ rails g model Like user:references micropost:references
Running via Spring preloader in process 4905
invoke active_record
create db/migrate/20180619073616_create_likes.rb
create app/models/like.rb
今回はログイン済みユーザー(user_idをもつユーザー)でないとコメントできないようにするためにreferences
でモデルを生成をしました。
また、Like
モデルはユーザーと投稿内容の両方が存在しなければいけないのでバリデーションも設けます。
class Like < ApplicationRecord
belongs_to :user
belongs_to :micropost
validates :user_id, presence: true
validates :micropost_id, presence: true
end
マイグレーションファイル
rails g model
コマンドによって、下記のマイグレーションファイルが作成されました。
class CreateLikes < ActiveRecord::Migration[5.0]
def change
create_table :likes do |t|
t.references :user, foreign_key: true
t.references :micropost, foreign_key: true
t.timestamps
end
end
end
-
t.references :user, foreign_key: true
- 実際のデータベース上では、
user_id
カラムとして存在しています
- 実際のデータベース上では、
-
t.references :micropost, foreign_key: true
- 実際のデータベース上では、
micropost_id
カラムとして存在しています
- 実際のデータベース上では、
foreign_key
は外部キー制約というもので、保存されるテーブルの整合性を高め、間違ったデータをできるだけ排除できるかという性質があります。
マイグレーションの実行
マイグレーションの実行をすることでテーブルを作成していきましょう。
$ rails db:migrate
== 20180619073616 CreateLikes: migrating ======================================
-- create_table(:likes)
-> 0.0059s
== 20180619073616 CreateLikes: migrated (0.0068s) =============================
likes
テーブルが作成されました。
モデル生成では、user:references micropost:references
と書きましたが
$ rails g model Like user:references micropost:references
実際にDBに作成されたlikes
テーブルのカラムには、
user_id
micropost_id
が、出来ているとわかります。
mysql> show tables;
+----------------------------------+
| Tables_in_microposts_development |
+----------------------------------+
| ar_internal_metadata |
| likes |
| microposts |
| relationships |
| schema_migrations |
| users |
+----------------------------------+
6 rows in set (0.00 sec)
mysql> describe likes;
+--------------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+----------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | YES | MUL | NULL | |
| micropost_id | int(11) | YES | MUL | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+--------------+----------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
reference型を使うメリット
reference型を使うメリットは、user
という名前でrails g model
して、user_id
というカラム名を自動で作成してくれることで、users
テーブルのid
を自動で参照(インデックス)してくれます。Rails便利。
以上です!
この記事を読んだ方に
この記事を読んで、誤っている箇所をみつけたり、追記した方がいい内容などありましたら、編集リクエストやコメント欄で指摘していただけると助かります。