rails generate migrationコマンドまとめ

RailsでDBスキーマ周りをいじろうとすると、たいてい`rails generate migration`コマンドあたりがでてくるんだけど、なんかいまいちどういう使い方ができるのか、分からなかったのでまとめてみる。

# 基本コマンド

```bash:command
# マイグレーションファイル作成コマンド
$ rails generate migration クラス名

# モデル作成
$ rails generate model モデル名
```

クラス名は何でもOKだけど「アクション+テーブル名」とかが慣例っぽいです。分かりやすければ良いかな。これで /db/migrate/タイムスタンプ_クラス名.rb というファイルが作れる。ここに、スキーマの変更点を記載すればOK。

モデルの新規作成は`model モデル名`。命名規則は[モデル名とテーブル名の規約](http://railsdoc.com/model)を参照。

generateは g と略すことができるので、ぜひ略そう。

# テーブルを作る

```bash:command
$ rails g model モデル名 フィールド:型:(unique|index) 以降必要なだけ
```

こんな感じのusersテーブルを作成したい場合

```bash:command
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field      | Type         | Null | Key | Default | Extra          |
+------------+--------------+------+-----+---------+----------------+
| id         | int(11)      | NO   | PRI | NULL    | auto_increment |
| uuid       | varchar(255) | YES  |     | NULL    |                |
| name       | varchar(255) | YES  |     | NULL    |                |
| created_at | datetime     | YES  |     | NULL    |                |
| updated_at | datetime     | YES  |     | NULL    |                |
+------------+--------------+------+-----+---------+----------------+
```

```bash:command
$ rails g model User uuid:string:unique name:string
```

こうすればOK。サロゲートキー（id）とレコードの作成日時／更新日時のタイムスタンプは自動で作られる。これ、NOT NULLはどうやって指定するんだろ…。

/db/migrate/ 以下にマイグレーションファイルが作成されるので、NOT NULLだったり、カラム名の修正とかをしたい場合は、ここで直接修正してしまう。

## 指定できる型

- string : 文字列
- text : 長い文字列
- integer : 整数
- float : 浮動小数
- decimal : 精度の高い小数
- datetime : 日時
- timestamp : タイムスタンプ
- time : 時間
- date : 日付
- binary : バイナリデータ
- boolean : Boolean

## マイグレーション実行＆ロールバック＆確認

このままだと、実際のDBには反映されないので、db:migrateコマンドを実行する。

```bash:command
# 実行
$ rake db:migrate
```

```bash:command
# ロールバック
$ rake db:rollback
```

```bash:command
# 確認
$ rake db:migrate:status

database: hoge_development

 Status   Migration ID    Migration Name
--------------------------------------------------
   up     20140909055128  Create users
   up     20140909055234  Create spots
   up     20140909055735  Create user spots
   up     20140909072813  Change options to user spot
```

# テーブルを削除する。

```bash:command
$ rails g migration DropUser
```

```ruby
class DropUser < ActiveRecord::Migration[5.0]
  def change
    drop_table :users
  end
end
```

ロールバックを効かせるため、以下のように up と down を明示しておくとよいと思います。

```ruby
class DropUser < ActiveRecord::Migration[5.0]
  def up
    drop_table :users
  end
  def down
    create_table :users do |t|
      t.string :uuid
      t.string :name
      t.timestamps
    end
  end
end
```

# テーブル名を変更する

すでに存在しているテーブルの名前を変更したくなった場合。

```bash:command
$ rails g migration RenameIssueToTask
```

```ruby:/db/migrate/20140909095843_rename_issue_to_task.rb
class RenameIssueToTask < ActiveRecord::Migration
  def change
    rename_table :issues, :tasks
  end
end
```

# 既存カラムを変更する

すでに存在しているテーブルのカラムを変更したくなった場合。

```bash:command
$ rails g migration ChangeColumnToUser
```

```ruby:/db/migrate/20140909095843_change_column_to_user.rb
class ChangeColumnToUser< ActiveRecord::Migration

  # 変更内容
  def up
    change_column :users, :uuid, :string, null: false, default: 0
  end

  # 変更前の状態
  def down
    change_column :users, :uuid, :string, null: true, default: 0
  end
end
```

この例は、UserモデルのuuidカラムをNOT NULL制約に変更した。`up`と`down`のメソッドによって、マイグレーションの適用前と適用後を明示的にできる。つまり、ロールバックすることができる。

どっかで、`migration クラス名`のクラス名部分に命名規則があって、それに従うと便利っぽいことが書かれていたんだけど、よく分からんので、普通に見て分かる名前でいいと思う。

## オプション

### NULL / NOT NULL

```ruby:/db/migrate/example.rb
# NULL
change_column :テーブル名, :カラム名, :型, null: true

# NOT NULL
change_column :テーブル名, :カラム名, :型, null: false
```

### インデックス

```ruby:/db/migrate/example.rb
change_column :テーブル名, :カラム名, :型, index: true
```

### デフォルト

```ruby:/db/migrate/example.rb
change_column :テーブル名, :カラム名, :型, default: "piyo"
```

すでに設定してあるデフォルト値を消す場合は `change_column_default` を利用する。さらに `false` を指定してしまいがちだが、 `nil` にしないと Integer の場合は DEFAULT 0 になってしまい、意図したものと違うことがあるので注意が必要。

```ruby:/db/migrate/example.rb
def up
  change_column_default :テーブル名, :カラム名, nil
end

def down
  change_column_default :テーブル名, :カラム名, 1
end
```

### 長さ

```ruby:/db/migrate/example.rb
# varchar(12)
change_column :テーブル名, :カラム名, :string, limit: 12
```

### コメント

Rails5からコメントを書けるようになった。

```ruby:/db/migrate/example.rb
change_column :テーブル名, :カラム名, comment: "コメントです"
```

### 小数部の精度を指定する

MySQL5.6.4以降、datetime型で小数部（ミリ秒）の精度指定をサポートしている。Railsも合わせてミリ秒に対応させているので、基本的には指定したほうが良さげ。

```ruby:/db/migrate/example.rb
def change
  create_table :hoges do |t|
    t.datetime :hoge_date, precision: 6

    t.timestamps precision: 6
  end
end
```

# カラム名を変更する

```ruby
rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名
```

この時、対象のカラムにインデックスがある場合、そちらも自動的に変更してくれる。便利。

# カラムを追加/削除する

piyoっていうstringなカラムを追加する。追加の場合は、作成時と同じでカラムを予め指定して作ることができる。

```bash:command
$ rails g migration AddColumnToUser piyo:string
```

```ruby:/db/migrate/20140909095843_add_column_to_user.rb
class AddColumnToUser < ActiveRecord::Migration
  def change

    # 追加
    add_column :users, :piyo, :string

    # 削除
    remove_column :users, :piyo, :string

    # まとめて削除
    remove_columns :users, :column_1, :column_2 [, ...]

    # 追加する場所を指定する場合
    add_column :users, :piyo, :string, :after => :uuid
  end
end
```

# インデックスを追加/削除する

Userモデルのnameカラムにインデックス追加したり削除したり。複合ユニークだったり。

```bash:command
$ rails g migration AddIndexToUser
```

```ruby:/db/migrate/20140909095843_add_index_to_user.rb
class AddIndexToUser < ActiveRecord::Migration
  def change

    # 追加
    add_index :users, :name

    # ユニーク追加
    add_index :users, :name, :unique => true

    # 削除
    remove_index :users, :name

    # 複合インデックスの場合
    add_index :users, [:name, :name2]

    # 複合ユニークの場合
    add_index :user_accounts, [:provider, :uid], :name => 'unique_provider_uid', :unique => true

  end
end
```

## 外部キーを作成・削除する

```
$ rails g model UserAccount user:references
```

`references` を指定することで外部キー制約を作ることができる。これで硬めのDBが作れるはず。

```ruby
class CreateUserAccounts < ActiveRecord::Migration[5.0]
  def change
    create_table :user_accounts do |t|
      t.references :user,  index: true, foreign_key: true

      t.timestamps
    end
  end
end
```

既存のテーブルに追加する場合は下記のマイグレーションコマンドで外部キーを追加できる。

```
$ rails g migration AddArticleToUsers article:references
```

```ruby
class AddRefUser < ActiveRecord::Migration
  def change
    add_reference :users, :article, foreign_key: true

    # 外部キーの削除はこちら
    remove_foreign_key :users, column: :article_id

    # カラムも一緒に削除する場合はこちら
    remove_reference :users, :article, foreign_key: true
  end
end
```

# ポリモーフィックを作る

Messageモデルをポリモーフィックとして作る。

```
$ rails g model message messagable:references{polymorphic}  message:text
```

```
class CreateMessages < ActiveRecord::Migration[5.0]
  def change
    create_table :messages do |t|
      t.references :messagable, polymorphic: true
      t.text :message

      t.timestamps
    end
  end
end
```

関連するモデルのリレーションの指定はこうする。

```
class Message < ActiveRecord::Base
  belongs_to :messagable, polymorphic: true
end

class Company < ActiveRecord::Base
  has_many :messages, as: :messagable
end

class User < ActiveRecord::Base
  has_many :messages, as: :messagable
end
```

UserとCompanyモデルがMessageモデルを複数所有するような感じ。