ActiveRecordで1対他の関連付けマイグレーションを作成する


目的

一つのテーブルに対して複数のテーブルを紐づけるモデルを作成する

環境

  • ruby 2.0.0p481
  • Rails 4.2

手順

前提

  • 以下のモデルを作成する
    COMPETITER
    NEWS
    ISSUE
    ISSUE_MST

  • 関連付け

    • COMPETITERは、複数のISSUE(論点)を持つ
    • COMPETITERは、複数のNEWS(ニュース)を持つ
    • ISSUEは一つのISSUE_MSTを持つ

モデルの作成

COMPETITORモデル

COMPETITORモデルは以下の定義とする

項目 物理名 データ型
キー id integer
画像ファイル名 img string
所属団体名称 party string
  • rails generateコマンドで以下のように表現する
rails g model Competitor img:string name:string party:string
rails g model Competitor img:string name:string party:string
Warning: You're using Rubygems 2.0.14 with Spring. Upgrade to at least Rubygems 2.1.0 and run `gem pristine --all` for better startup performance.
Running via Spring preloader in process 22853
      invoke  active_record
      create    db/migrate/20160717072810_create_competitors.rb
      create    app/models/competitor.rb
      invoke    test_unit
      create      test/models/competitor_test.rb
      create      test/fixtures/competitors.yml

関連するモデルの作成

NEWS_POSTSモデル

NEWS_POSTSモデルは以下の定義とする
1対多の関連付けを行う場合、多側のモデル名は複数形で定義する

項目 物理名 データ型
キー id integer
画像ファイル名 img string
所属団体名称 party string
COMPETITORへの外部キー competitor_id references

COMPETITORと異なるのは、外部キーを追加する必要がある点
その場合、references型のデータとして外部モデル名をモデル作成時に項目につかする

  • rails generateコマンドで以下のように表現する
rails g model NewsPosts title:string link:string discription:text competitor:references

これだけで自動的にインデックスと外部参照キーのカラムが作成される
自動生成されるカラムは
参照先モデル名_id
となる

  • 以下のようなマイグレーションファイルが作成される
マイグレーションファイル
class CreateNewsPosts < ActiveRecord::Migration
  def change
    create_table :news do |t|
      t.string :title
      t.string :link
      t.text :discription
      t.references :competitor, index: true, foreign_key: true

      t.timestamps null: false
    end
  end
end

外部キーがcompetitorへ作成されていることが確認できる

  • モデル側を確認すると、多側の関連テーブルはbelongs_toが追加されている
news
class NewsPosts < ActiveRecord::Base
  belongs_to :competitor
end
  • 関連される側のモデルに、has_manyを追加し、1対多の関連付けがモデルに指定される
competitor
class Competitor < ActiveRecord::Base
  has_many:news
end

ISSUESモデル

ISSUESモデルは以下の定義とする

項目 物理名 データ型
キー id integer
OK数 ok integer
NG数 ng integer
COMPETITORへの外部キー competitor_id references
ISSUE_MSTへの外部キー issue_mst_id references

newsと同じように1対他の関連付けを指定する
今回の場合、ISSUE_MSTへも関連付けを持つ

rails g model issues ok:integer ng:integer competitor:references issue_mst:references

ISSUES_MSTモデル

ISSUEは一つのISSUE_MSTを持つ

項目 物理名 データ型
キー id integer
論点名 issue_name string
rails g model IssueMst issue_name:string

マイグレーションを実行する

bundle exec rake db:migrate

作成されたDBを確認する

WEBRickを起動したのち、以下のコマンドでDBコンソールを起動する

rails dbconsole
Warning: You're using Rubygems 2.0.14 with Spring. Upgrade to at least Rubygems 2.1.0 and run `gem pristine --all` for better startup performance.
SQLite version 3.8.5 2014-08-15 22:37:57
Enter ".help" for usage hints.
sqlite> 

sqliteで、作成したDBを確認できる

sqlite> .tables
competitors        issues             schema_migrations
issue_msts         news    
sqlite> .schema
CREATE TABLE "schema_migrations" ("version" varchar NOT NULL);
CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version");
CREATE TABLE "competitors" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "img" varchar, "name" varchar, "party" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE TABLE "news" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "title" varchar, "link" varchar, "discription" text, "competitor_id" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE INDEX "index_news_on_competitor_id" ON "news" ("competitor_id");
CREATE TABLE "issue_msts" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "issue_name" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE TABLE "issues" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "ok" integer, "ng" integer, "competitor_id" integer, "issue_mst_id" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL);
CREATE INDEX "index_issues_on_competitor_id" ON "issues" ("competitor_id");
CREATE INDEX "index_issues_on_issue_mst_id" ON "issues" ("issue_mst_id");

 修正

誤って作成したモデルを削除したい

以下のモデルは誤って作成されたモデル

rails g model News title:string link:string discription:text
Warning: You're using Rubygems 2.0.14 with Spring. Upgrade to at least Rubygems 2.1.0 and run `gem pristine --all` for better startup performance.
Running via Spring preloader in process 22864
      invoke  active_record
      create    db/migrate/20160717073745_create_news.rb
      create    app/models/news.rb
      invoke    test_unit
      create      test/models/news_test.rb
      create      test/fixtures/news.yml

作りなおすため、いったん削除する
rails destroy model コマンドを使用する

rails destroy model News title:string link:string discription:text
Warning: You're using Rubygems 2.0.14 with Spring. Upgrade to at least Rubygems 2.1.0 and run `gem pristine --all` for better startup performance.
Running via Spring preloader in process 22889
      invoke  active_record
      remove    db/migrate/20160717073745_create_news.rb
      remove    app/models/news.rb
      invoke    test_unit
      remove      test/models/news_test.rb
      remove      test/fixtures/news.yml

参考文献

Railsガイド
Active Record マイグレーション
http://railsguides.jp/active_record_migrations.html