ChatSpaceのDB設計
ChatSpaceの機能を洗い出す
ChatSpaceを使ってみて、どのような機能があるか洗い出す。先に必要な機能を把握してからデータベース設計をする。
例)Pictweetの場合
- ユーザー管理機能
- ツイート機能
- コメント機能
必要なテーブルを考える
機能ごとに必要なテーブルを考えてみる。チャットのメッセージを保存するテーブル(messagesテーブル)を例にあげる。messagesテーブルには、チャットのメッセージに関する、「誰が送ったか」、「どのグループで送ったか」、「いつ送ったか」、「どのような内容か」を保存する必要がある。
次に、他のテーブルに保存されている情報と、メッセージの関連について考えてみる。
メッセージはユーザー、グループと関連づいていることがわかるので、アソシエーションを定義するためのuser_idとgroup_idというカラムが必要となる。
どういった内容をコメントをしたのかは、body
カラムを作成する。また、画像の送信も出来るのでimage
カラムも用意する。いつメッセージしたのかは、デフォルトでマイグレーションファイルに記述されているtimestampsを利用する。
結果として、messagesテーブルは以下のような構成になる。
column | type |
---|---|
body | text |
image | string |
group_id | integer |
user_id | integer |
このようにして、データベース設計を行う。
アソシエーションや、null許可、indexを張るかも考慮し設計する
中間テーブルについて
ChatSpaceにおいては1対多とは別種のアソシエーションを用いる。
具体的に考えてみる。
あるユーザーは複数のグループに所属する。
あるグループには複数ユーザーが所属する。
この例における、ユーザーとグループの関係を 多対多 と言う。
この種類のアソシエーションを定義するには、中間テーブル が必要になる。
多対多
『Instagram』などのように、ひとつの写真に複数のタグ付けができるSNSをイメージしてみる。こうしたタグ付け機能を実現するには3つのテーブルが必要である。タグを保存するテーブル、写真を保存するテーブル、そして「どの写真にどのタグが登録されているか」を保存するテーブルである。
このうち写真やタグを保存するテーブルの名前はそのままtagsテーブル、photosテーブルで良い。「どの写真にどのタグが ~」のテーブルは、慣習的にphotos_tagsテーブル、と名付ける。関係する2つのテーブルをアンダーバーでくっつけている。
それぞれのテーブルに保存されているレコードの関係性は以下のようになる。
ひとつの写真には「東京/カフェ/おしゃれ」のように複数のタグが属している。
また同じ「東京」のタグに対してもたくさんの写真が投稿されるので、ひとつのタグに複数の写真が属しているとも言える。
このような関係を多対多の関係と呼びます。多対多の関係を表現するには、photos_tagsテーブルのような中間テーブルが必要。
中間テーブルには、「どの写真がどのタグと関連づいているか」という情報が記載されていることになる。
ひとつのレコードには「photos_id × tags_id」の組み合わせが記録され、全ての写真とタグの組み合わせの数分、レコードが蓄積されていく。10個の写真にそれぞれ3つずつタグが付いている場合、全ての関係性を表すのに中間テーブルのレコードは30個生成される。
has_many throughオプション
has_manyのthroughオプションは、モデルに多対多の関連を定義するときに利用する。through
という名前のとおり、「〜を経由する」という意味。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# app/models/photo.rb
class Photo < ActiveRecord::Base
has_many :photos_tags
has_many :tags, through: :photos_tags
end
# app/models/tag.rb
class Tag < ActiveRecord::Base
has_many :photos_tags
has_many :photos, through: :photos_tags
end
# app/models/photos_tag.rb
class PhotosTag < ActiveRecord::Base
belongs_to :photo
belongs_to :tag
end
|
上記のようなアソシエーションを定義することで、自動的に以下のようなメソッドが使えるようになる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#通常レコードの作成
tag1 = Tag.create(name: "東京")
tag2 = Tag.create(name: "おしゃれ")
photo1 = Photo.create(image: "cool_cafe.jpg", location: "桜ヶ丘")
# 多対多関係を定義したレコードの作成
tag1.photos.create(image: "cute_shop.jpg", location: "宇田川町")
# リレーションの追加
tag1.photos << photo1
photo1.tags << tag2
# リレーションを利用したレコードの取得
photo1.tags
# => #<Tag id:1, name:"東京">,#<Tag id:2, name:"おしゃれ">
|
・2〜4行目
ここでは単体のインスタンスを生成している。今回使用する例は、nameプロパティを持ったtagインスタンスとimage及びlocationプロパティを持ったphotoインスタンス。これらの間には多対多の関係が定義されている。
・8行目
多対多の関係性を利用し、tag1に関係したphotoインスタンスを新たに生成している。「 tag1.photos
.create 」と、複数形になっていることに注意する。
・12〜13行目
後からインスタンス同士を関連付けることも可能。「<<メソッド」を使用するとこのように簡単に実現することができる。
12行目では、tag1と関係しているphotosの配列に、新たにPhotoクラスのインスタンスを追加することでリレーションを生成している。
また13行目では同様に、photo1と関係しているtagsの配列に対し、新たにtag2とのアソシエーションを追加している。
・17行目
リレーションしている要素を全て出力することもできる。上記の例だと、photo1は12・13行目でそれぞれtag1・tag2に関連付けられているので、返り値としてtag1ならびにtag2のインスタンスが出力されている。
また、has_manyメソッドには他にも次のようなオプションを指定できる。
オプション名 | 用途 |
---|---|
class_name | 関連するモデルのクラス名を指定でき、関連名(photos_tags等、has_manyの直後に書くもの)と参照先のクラス名(PhotosTagのようなモデル名)を異なるものにできる |
foreign_key | 参照先を参照する外部キーの名前を指定できる(デフォルトは、参照先のモデル名_id) |
dependent | 親モデルのデータを消したら関連するモデルのデータも連動して消したいときに使用します。destroyとdelete_allでひとつひとつ消していくか、一気に消すかを指定できる |
source | 関連テーブルから先のモデルにアクセスするための(関連モデルから見た)関連名を指定できる |
以上の中間テーブルの使い方を加味した上で、ChatSpaceのグループ機能を実現するためのデータベース設計を考える。
READMEに記載する
考えたデータベース設計をREADMEに記述していく。
READMEについて
READMEはアプリケーションのディレクトリに含まれるファイルのこと。アプリケーション開発において重要な役割がある。
README
READMEとは、マークダウンで記述され、ソフトウェアの仕様、規格、インストール方法などを文書化したもの。rails newをした際に自動生成される。
マークダウン
マークダウンとは、文書を記述するための軽量マークアップ言語のひとつ。マークダウンで記述されたものは、HTMLに変換される。Qiitaなどマークダウンで記述できるサービスも多くあるので書き方を調べて、身につける。以下はマークダウンについての参考記事。
READMEにDB設計を記載
ブランチを作成する
README編集のためのブランチを作成する。ブランチ名は自由に決められますが、第三者に見せる時や自身で振り返る時に、何をしているブランチなのかわかるようなブランチ名にすることが重要。
必ずブランチを作成してからREADMEへの記述を始める。後からブランチを作成してしまうとうまくプルリクエストを作れず、やり直しになる可能性がある
READMEにデータベース設計を記述
READMEはアプリケーションフォルダ内のREADME.md
に書く。READMEはマークダウンで書くことができるので、見出しやテーブルを使って見やすいREADMEを作成する。READMEには、テーブルのカラムと型、オプションを記述。また、アソシエーションも必ず記入する。
ここではREADMEの記載のみを行う。実際のモデルやテーブルおよびそのカラムは後で作成する。
例として、ChatSpaceでグループとユーザーの中間テーブルにあたるgroups_usersテーブルのマークダウンの例を以下に示す。
README.mdに記述したい項目は以下になる。
- テーブル名
- カラム名
- カラムの型
- カラムのオプション(null false制約など)
- アソシエーション
これらをマークダウンで記述すると以下のようになる。
1 2 3 4 5 6 7 8 9 10 |
## groups_usersテーブル
|Column|Type|Options|
|------|----|-------|
|user_id|integer|null: false, foreign_key: true|
|group_id|integer|null: false, foreign_key: true|
### Association
- belongs_to :group
- belongs_to :user
|
このようにマークダウンを記述すると以下のように反映される。
groups_usersテーブル
Column | Type | Options |
---|---|---|
user_id | integer | null: false, foreign_key: true |
group_id | integer | null: false, foreign_key: true |
Association
- belongs_to :group
- belongs_to :user
マークダウンが反映されているかどうかはGitHubで確認。