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


概要

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

テーブル作成

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

作成するテーブルの関係

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

作成手順(Generate)と作成されるマイグレーション、モデルファイルの中身

ヘッダテーブル
bundle exec rails g model header title:string

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

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
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で作成されるファイル

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
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で作成されるファイル

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
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で作成されるファイル

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
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で作成されるファイル

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で作成されるファイル

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
app/models/guest.rb
class Guest < ActiveRecord::Base
end

モデルへのスキーマコメント付与

annotateGemをバンドルしておけば、bundle exec annotateで、モデルにスキーマ定義をコメントとして付与できます。
上記、app/models/user.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