Edited at

rails generate migrationコマンドまとめ

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


基本コマンド


command

# マイグレーションファイル作成コマンド

$ rails generate migration クラス名

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


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

モデルの新規作成はmodel モデル名。命名規則はモデル名とテーブル名の規約を参照。

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


テーブルを作る


command

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


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


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 | |
+------------+--------------+------+-----+---------+----------------+


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コマンドを実行する。


command

# 実行

$ rake db:migrate


command

# ロールバック

$ rake db:rollback


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



テーブルを削除する。


command

$ rails g migration DropUser


class DropUser < ActiveRecord::Migration[5.0]

def change
drop_table :users
end
end

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

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


テーブル名を変更する

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


command

$ rails g migration RenameIssueToTask



/db/migrate/20140909095843_rename_issue_to_task.rb

class RenameIssueToTask < ActiveRecord::Migration

def change
rename_table :issues, :tasks
end
end


既存カラムを変更する

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


command

$ rails g migration ChangeColumnToUser



/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制約に変更した。updownのメソッドによって、マイグレーションの適用前と適用後を明示的にできる。つまり、ロールバックすることができる。

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


オプション


NULL / NOT NULL


/db/migrate/example.rb

# NULL

change_column :テーブル名, :カラム名, :, null: true

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



インデックス


/db/migrate/example.rb

change_column :テーブル名, :カラム名, :, index: true



デフォルト


/db/migrate/example.rb

change_column :テーブル名, :カラム名, :, default: "piyo"


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


/db/migrate/example.rb

def up

change_column_default :テーブル名, :カラム名, nil
end

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



長さ


/db/migrate/example.rb

# varchar(12)

change_column :テーブル名, :カラム名, :string, limit: 12


コメント

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


/db/migrate/example.rb

change_column :テーブル名, :カラム名, comment: "コメントです"



小数部の精度を指定する

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


/db/migrate/example.rb

def change

create_table :hoges do |t|
t.datetime :hoge_date, precision: 6

t.timestamps precision: 6
end
end



カラム名を変更する

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

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


カラムを追加/削除する

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


command

$ rails g migration AddColumnToUser piyo:string



/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カラムにインデックス追加したり削除したり。複合ユニークだったり。


command

$ rails g migration AddIndexToUser



/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が作れるはず。

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

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モデルを複数所有するような感じ。