Railsで関係性をもったテーブルの作成方法

# 概要
RailsのGenerateでテーブルを作成するとき、1対多とか、多対多の関係を持ったテーブル作成、モデルの書き方に迷った時のためのメモ

# テーブル作成
RailsのGenerateを使って、モデルとマイグレーションファイルを作成します。
ついでに、モデルには関連定義（has_many、belongs_toなど）を記述しておきます。
## 作成するテーブルの関係

| テーブル | 関係 | テーブル |
|:-----------:|:------------:|:------------:|
|ヘッダテーブル|1対多|詳細テーブル|
|所属テーブル|1対多|所属テーブル|
|所属テーブル|多対多|ユーザテーブル|
|ユーザテーブル|同定義|ゲストテーブル|

## 作成手順（Generate）と作成されるマイグレーション、モデルファイルの中身
**ヘッダテーブル**
`bundle exec rails g model header title:string`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_headers.rb
class CreateHeaders < ActiveRecord::Migration
  def change
    create_table :headers do |t|
      t.string :title

      t.timestamps null: false
    end
  end
end
```
```rb:app/models/header.rb
class Header < ActiveRecord::Base
  has_many :details  # <== 関係を追記
end
```
**詳細テーブル**
`bundle exec rails g model detail header:refelences name:string stock:integer`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_details.rb
class CreateDetails < ActiveRecord::Migration
  def change
    create_table :details do |t|
      t.references :header
      t.string :name
      t.integer :stock

      t.timestamps null: false
    end
  end
end
```
```rb:app/models/detail.rb
class Detail < ActiveRecord::Base
  belongs_to :header  # <== 関係を追記
end
```
**所属テーブル**
`bundle exec rails g model group name:string description:text group:references`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_groups.rb
class CreateGroups < ActiveRecord::Migration
  def change
    create_table :groups do |t|
      t.string :name
      t.text :description
      t.references :group, index: true

      t.timestamps null: false
    end
    add_foreign_key :groups, :groups
  end
end
```
```rb:app/models/group.rb
class Group < ActiveRecord::Base
  belongs_to :group   # <== 関係を追記
  has_many   :groups  # <== 関係を追記
  has_and_belongs_to_many :users  # <== 関係を追記
end
```
**ユーザテーブル**
`bundle exec rails g model user  name:string email:string`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_users.rb
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps null: false
    end
  end
end
```
```rb:app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :groups  # <== 関係を追記
end
```
**所属-ユーザ対照テーブル**
`bundle exec rails g migration create_groups_users group:references user:references`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_groups_users.rb
class CreateGroupsUsers < ActiveRecord::Migration
  def change
    create_table :groups_users, id: false do |t|
      t.references :group, index: true, null: false
      t.references :user,  index: true, null: false
    end
    add_foreign_key :groups_users, :groups
    add_foreign_key :groups_users, :users
  end
end
```
**ゲストテーブル**
`bundle exec rails g model guest  name:string email:string`

上記Generateで作成されるファイル

```rb:db/migrate/xxxxx_create_guests.rb
class CreateGuests < ActiveRecord::Migration
  def change
    create_table :guests do |t|
      t.string :name
      t.string :email

      t.timestamps null: false
    end
  end
end
```
```rb:app/models/guest.rb
class Guest < ActiveRecord::Base
end
```

## モデルへのスキーマコメント付与
`annotate`Gemをバンドルしておけば、`bundle exec annotate`で、モデルにスキーマ定義をコメントとして付与できます。
上記、`app/models/user.rb`の場合、以下のようになります。

```rb:app/models/user.rb
# == Schema Information
#
# Table name: users
#
#  id         :integer          not null, primary key
#  name       :string(255)
#  email      :string(255)
#  created_at :datetime         not null
#  updated_at :datetime         not null
#

class User < ActiveRecord::Base
  has_and_belongs_to_many :groups
end
```

これで、カラムを確認するために、わざわざスキーマファイルを見る必要が無くなります。

# DB作成とマイグレート
開発環境`development`へのDB作成、マイグレートを行います。

**DB作成**
`bundle exec rake db:create RAILS_ENV=development`
**マイグレート**
`bundle exec rake db:migrate RAILS_ENV=development`