読者です 読者をやめる 読者になる 読者になる

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

Railsのmigrationの基本とレシピ集

Rails初級 Rails Migration

RailsのMigrationの基本的なことから、カラム追加/削除、インデックス追加、NULL制約、カラム名変更などのレシピ集をまとめました。

動作確認

  • Rails 4.1

目次

2. Migrationのレシピ集

2.1. カラムの追加(add_column)
2.2. カラムの削除(remove_column)
2.3. データ型の変更(change_column)
2.4. インデックスやユニーク制約の追加/削除(add_index/remove_index)
2.5. NULL制約の追加/削除(change_column_null)
2.6. デフォルト値の追加/削除(change_column_default)
2.7. カラム名の変更(rename_column)
2.8. テーブルの作成(create_table)
2.9. テーブルの削除(drop_table)
2.10. テーブル名の変更(rename_table)
2.11. 商用リリース後の初期データの投入

1. Migrationの基礎

1.1. migrationファイルの作成

Railsのmigrationはデータベースのスキーマの設定管理を一貫して規則正しく行うための基盤です。
migrationファイルを作成するには、「手動でファイルを作成する方法」と「$ rails generateコマンドで作成する方法」の2つの作成方法があります。
$ rails generateコマンドで作成する方がエラーが発生しづらいためそちらの方法でのファイル作成方法を説明します。

Railsジェネレートコマンドも
「モデルとマイグレーションファイルを作成する$ rails g model
「マイグレーションファイルのみを作成する$ rails g migration
があります。

ggenerateのショートカットです。

モデルとマイグレーションファイルを作成

以下のコマンドでArticleモデルとマイグレーションファイルを作成します。
また、Articleモデルには、String型のtitle、Text型のcontentカラムがあります。

$ rails g model Article title:string content:text
      invoke  active_record
      create    db/migrate/20140808181112_create_articles.rb
      create    app/models/article.rb
      invoke    test_unit
      create      test/models/article_test.rb
      create      test/fixtures/articles.yml

マイグレートファイルはdb/migrate配下に作成されます。
また、ファイル名には、YYYYMMDDHHmmSSが付与され、ファイル名の重複や、マイグレートファイルがDBに適用済みかどうかを確認するために使われます。

では、上記のコマンドで作成されたマイグレーションファイルを見てみましょう。
マイグレーションファイルは、ActiveRecord::Migrationを継承している必要があります。
メソッドは、changeメソッド、もしくは、updownメソッを定義している必要があります。
その中で、テーブル作成/削除、カラム追加/削除などを行います。今回は、create_tableメソッドでarticlesというテーブルを作成し、ブロック内でカラムを追加しています。

timestampsは、レコードの作成時刻のcreated_atと更新時刻のupdated_atをカラムを作成してくれます。明示的に追加しなくても自動でマイグレーションファイルに追加され、また、カラムの値は自動で更新されます。

各メソッドの詳細は、本ページのレシピ集に記載してます。

# db/migrate/20140808181112_create_articles.rb
class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

updownは、changeメソッドの代わりに使います。
uprake db:migrateの実行時に実行され、downrake db:rollback時に実行されます。
changeメソッドのときは、内部的に可逆性を推定して実施しますが、必ずしも推定できない場合はup/downで定義しておくことによりロールバックができるようになります。ロールバックは必須ではないので、わざわざup/downを実施しなくてもよいです。
上記のマイグレーションファイルをup/downで書き直した例は次の通りです。

# db/migrate/20140808181112_create_articles.rb
class CreateArticles < ActiveRecord::Migration
  def up
    create_table :articles do |t|
      t.string :title
      t.text :content

      t.timestamps
    end
  end

  def down
    drop_table :articles
  end
end
マイグレーションファイルのみを作成

マイグレーションファイルのみを作成する場合は、rails g migrationです。
内容は上記で説明したので省略します。

$ rails g migration create_articles title:string content:text
      invoke  active_record
      create    db/migrate/20140808181236_create_articles.rb


作成されたマイグレーションファイルを確認します。
内容はrails g modelと同じです。

# db/migrate/20140808181236_create_articles.rb
class CreateArticles < ActiveRecord::Migration
  def change
    create_table :articles do |t|
      t.string :title
      t.text :content
    end
  end
end

1.2. マイグレートの実施 rake db:migrateコマンド

rake db:migrateコマンドで適用していないマイグレーションファイルを全て適用することができます。

$ rake db:migrate

# RAILS_ENV をしていすることでマイグレートする環境を指定できます
$ rake db:migrate RAILS_ENV=test             # test環境に適用
$ rake db:migrate RAILS_ENV=production  # production環境に適用


適用したマイグレートファイル1つだけ未適用状態にする(ロールバック)
downメソッドが定義されていない場合は失敗する場合もあります。詳細は上記を参照して下さい。

$ rake db:rollback

最初の状態までロールバックする

$ rake db:migrate VERSION=0

全てのテーブルとデータをを削除し、スキーマ(schema.rbの内容)を適用する。ロールバックできない場合に使える。
本当にどうしようもない場合は、直接データベースにアクセスし、テーブルを削除して、マイグレートを適用させましょう。
schema.rbはdb:migrateの結果をマージしたファイルです。

$ rake db:reset


1.3. マイグレートの適用状況確認 rake db:migrate:statusコマンド

次のコマンドで、現在データベースに適用されているマイグレーションファイルを確認します。
Migration IDがマイグレーションファイルのYYYYMMDDHHmmSSに対応しています。

$ rake db:migrate:status 

database: /Users/nipe0324/rails_project/db/development.sqlite3

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20141008133536  Create pictures
   up     20141008133734  Add attachment photo to pictures


1.4. データの投入 rake db:seedコマンド

初期データをデータベースに投入するために、db/seeds.rbが存在します。
この中はRubyが記載でき、Rubyでモデルを作成します。

※本番環境などデータを削除することができない場合は、このdb/seeds.rbを使うことは適切ではありません。「商用リリース後の初期データの投入」を参照して下さい。

seeds.rbを記載したら、rake db:seedコマンドで実行することができます。

$ rake db:seed

ここではサンプルとして、3つの記事(Articleオブジェクト)を作成して適用します。

### モデルとマイグレーションファイルを作成
$ rails g model Article title:string content:text

### マイグレートを実施
$ rails db:migrate

### db/seeds.rbに初期データ投入を記載
$ vim db/seeds.rb
# 記事を3つ作成
Article.create!( title: "記事1", content: "内容1" )
Article.create!( title: "記事2", content: "内容2" )
Article.create!( title: "記事3", content: "内容3" )

### db/seeds.rbを適用
$ rake db:seed

### コンソールでデータが入ったことを確認
$ rails c
Loading development environment (Rails 4.1.4)
> Article.all
=> #<ActiveRecord::Relation [#<Article id: 1, title: "記事1", content: "内容1", created_at: "2014-08-08 19:41:31", updated_at: "2014-08-08 19:41:31">, #<Article id: 2, title: "記事2", content: "内容2", created_at: "2014-08-08 19:41:31", updated_at: "2014-08-08 19:41:31">, #<Article id: 3, title: "記事3", content: "内容3", created_at: "2014-08-08 19:41:31", updated_at: "2014-08-08 19:41:31">]>


1.5. マイグレーションで使えるデータ型一覧

rails generator modelrails generator migrationコマンドで使えるデータ型として以下のものがあります。

integer 整数
float 浮動小数
decimal 制度の高い小数

string 文字列
text  長い文字列
binary バイナリデータ

datetime 日時
timestamp より細かい日時
date 日付
time 時間

boolean Boolean型(true or false)

primary_key 主キー
references 外部キー

2. Migrationのレシピ集

2.1 カラムの追加(add_column)

articlesテーブルにuser_idカラムを追加してみます。

$ rails g migration add_user_id_to_articles user_id:integer
      invoke  active_record
      create    db/migrate/20140808182214_add_user_id_to_articles.rb

作成されたマイグレーションファイルを確認しましょう。

# db/migrate/20140808182214_add_user_id_to_articles.rb 
class AddColumnToArticles < ActiveRecord::Migration
  def change
    # [形式] add_column(テーブル名, カラム名, データ型)
    add_column :articles, :user_id, :integer
  end
end

さらに、add_columnには次のオプションを指定できます。

  • null: true ... NOT NULL制約を削除
  • null: false ... NOT NULL制約を追加
  • limit: size ... フィールドのサイズに対する制限を設定
  • default: [val] ... [val] に設定した値をレコード作成時のカラムのデフォルト値とする

さらにさらに、decimal型の場合は追加で以下のオプションも指定できます。
- precision: [num], scale: [num] ... precisionは格納される桁数、scaleはその桁数のどこを小数点位置にするかを設定
 ※ 例えば、precision: 5, scale: 2 の場合、 5桁で小数点は2桁目のため、格納できる値は -999.99〜+999.99となる



2.2. カラムの削除(remove_column)

articlesテーブルにuser_idカラムを削除してみます。

$ rails g migration remove_user_id_to_articles user_id
      invoke  active_record
      create    db/migrate/20140808182248_remove_user_id_to_articles.rb

作成されたマイグレーションファイルを見てみましょう。

#db/migrate/20140808182248_remove_user_id_to_articles.rb
class RemoveColumnToArticles < ActiveRecord::Migration
  def change
    # [形式] remove_column(テーブル名, カラム名)
    remove_column :articles, :user_id
  end
end

※ ロールバック時にカラムの追加方法が分からないため$ rake db:rollbackでエラーになります。もし、rollbackをしたい場合、up/downメソッドを定義し、downメソッド内でテーブルを作成する必要があります。


2.3. データ型の変更(change_column)

$ rails g migration change_datatype_title_of_articles
      invoke  active_record
      create    db/migrate/20140808183810_change_datatype_title_of_articles.rb

マイグレーションファイルにchange_columnメソッドを追加します。

# db/migrate/20140808183810_change_datatype_title_of_articles.rb
class ChangeDatatypeTitleOfArticles < ActiveRecord::Migration
  def change
    # [形式] change_column(テーブル名, カラム名, データタイプ, オプション)
    change_column :articles, :title, :text

    # オプション
    # limit - カラム長の最大数
    # change_column :articles, :title, :text, limit: 120

    # default - カラムのデフォルト値を設定。NULLにしたい場合は、nilを指定
    # change_column :articles, :title, :text, default: "タイトルがありません"

    # null - null制約を設定。false -> null制約がON。true -> null制約がOFF
    # change_column :articles, :title, :text, null: true
  end
end

2.4. インデックスやユニーク制約の追加/削除(add_index/remove_index)

articlesテーブルのtitleカラムにindexを追加しています。

$ rails g migration add_name_index_to_articles
      invoke  active_record
      create    db/migrate/20140808183810_add_name_index_to_articles.rb

マイグレーションファイルにadd_indexを追加します。

$ cat db/migrate/20140808183810_add_name_index_to_articles.rb
class AddNameIndexToArticles < ActiveRecord::Migration
  def change
    add_index :articles, :name
  # add_index :articles, :name, unique: true ユニーク制約も付加可能
  # add_index :articles, [:user_id, :created_at] 配列を使うことにより複合インデックスを設定可能
  end
end


2.5. NULL制約の追加/削除(change_column_null)

NULL制約の追加や削除のみを設定するにはchange_column_nullメソッドを使えば簡単です。

# usersテーブルのnicknameを "NULL" を許可しない(NOT NULL制約を追加)
change_column_null :users, :nickname, false

# usersテーブルのnicknameを "NULL" を許可する
change_column_null :users, :nickname, true


2.6. デフォルト値の追加/削除(change_column_default)

カラムのデフォルト値の追加や削除のみを設定するにはchange_column_defaultメソッドを使えば簡単です。

# suppliersテーブルのqualificationカラムのデフォルト値を 'new' を設定
change_column_default :suppliers, :qualification, 'new'

# accountsテーブルのauthorizedカラムのデフォルト値を 1 を設定
change_column_default :accounts, :authorized, 1

# usersテーブルのemailカラムのデフォルト値に NULL を設定
change_column_default :users, :email, nil

2.7. カラム名の変更(rename_column)

カラム名を "title" から "changed_title" へ変更しています。

$ rails g migration rename_title_column_to_articles
      invoke  active_record
      create    db/migrate/20140808184723_rename_title_column_to_articles.rb

マイグレーションファイルにrename_columnを追加します。

$ cat db/migrate/20140808184723_rename_title_column_to_articles.rb
class RenameTitleColumnToArticles < ActiveRecord::Migration
  def change
    # [形式] rename_column(テーブル名, 変更前のカラム名, 変更後のカラム名)
    rename_column :articles, :title, :changed_title
  end
end


2.8. テーブルの作成(create_table)

usersテーブルを作成しています。

$ rails g migration create_users name:string email:string
      invoke  active_record
      create    db/migrate/20140808185345_create_users.rb


マイグレーションを確認します。timestampsがない場合は追加して下さい。

$ cat  db/migrate/20140808185345_create_users.rb
class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :name
      t.string :email

      t.timestamps
    end
  end
end


2.9. テーブルの削除(drop_table)

usersテーブルを削除します。

$ rails g migration drop_users
      invoke  active_record
      create    db/migrate/20140808185551_drop_users.rb

マイグレーションファイルにdrop_tableを追加します。

$ cat db/migrate/20140808185551_drop_users.rb
class DropUsers < ActiveRecord::Migration
  def change
    drop_table :users
  end
end

※ロールバック時に、テーブルの作成方法が分からないため$ rake db:rollbackでエラーになります。もし、rollbackをしたい場合、up/downメソッドを定義し、downメソッド内でテーブルを作成する必要があります。


2.10. テーブル名の変更(rename_table)

テーブル名を "articles" から "posts" へ変更します。

$ rails g migration rename_articles_to_posts
      invoke  active_record
      create    db/migrate/20140808190856_rename_articles_to_posts.rb

マイグレーションにrename_tableを追加しましょう。

# db/migrate/20140808190856_rename_articles_to_posts.rb
class RenameArticlesToPosts < ActiveRecord::Migration
  def change
    rename_table :articles, :posts
  end
end


2.11. 商用リリース後の初期データの投入

初回に商用リリースをするときにdb/seeds.rbは適用済みであると思います。
そのため、その後にテーブルを追加し、その初期データを投入したいときにdb/seeds.rbを使うことができません。

所用リリース後に初期データを投入するためには、次のようにマイグレートファイルに初期データを投入するコードを作成します。
ここでは、categoriesテーブルを作成したのを前提として、初期のカテゴリーを追加します。

$ rails g migration insert_initial_categories_into_categories
      invoke  active_record
      create    db/migrate/20140808190856_insert_initial_categories_into_categories.rb

マイグレーションにrename_tableを追加しましょう。

# db/migrate/20140808190856_insert_initial_categories_into_categories.rb
class InsertInitialCategoriesIntoCategories < ActiveRecord::Migration
  def change
    names = %w(食費 日用品 交通費 交際費 税金)
    names.each do |name|
      Category.create name: name
    end
  end
end

参考文献

以上です。
よく分からない箇所や間違いがありましたら、コメントをいただけると直に対応します。