はじめに
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_idmicropost_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便利。
以上です!
この記事を読んだ方に
この記事を読んで、誤っている箇所をみつけたり、追記した方がいい内容などありましたら、編集リクエストやコメント欄で指摘していただけると助かります。