RailsでDBスキーマ周りをいじろうとすると、たいていrails generate migration
コマンドあたりがでてくるんだけど、なんかいまいちどういう使い方ができるのか、分からなかったのでまとめてみる。
基本コマンド
# マイグレーションファイル作成コマンド
$ rails generate migration クラス名
# モデル作成
$ rails generate model モデル名
クラス名は何でもOKだけど「アクション+テーブル名」とかが慣例っぽいです。分かりやすければ良いかな。これで /db/migrate/タイムスタンプ_クラス名.rb というファイルが作れる。ここに、スキーマの変更点を記載すればOK。
モデルの新規作成はmodel モデル名
。命名規則はモデル名とテーブル名の規約を参照。
generateは g と略すことができるので、ぜひ略そう。
テーブルを作る
$ rails g model モデル名 フィールド:型:(unique|index) 以降必要なだけ
こんな感じのusersテーブルを作成したい場合
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 | |
+------------+--------------+------+-----+---------+----------------+
$ 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コマンドを実行する。
# 実行
$ rake db:migrate
# ロールバック
$ rake db:rollback
# 確認
$ 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
テーブルを削除する。
$ 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
テーブル名を変更する
すでに存在しているテーブルの名前を変更したくなった場合。
$ rails g migration RenameIssueToTask
class RenameIssueToTask < ActiveRecord::Migration
def change
rename_table :issues, :tasks
end
end
既存カラムを変更する
すでに存在しているテーブルのカラムを変更したくなった場合。
$ rails g migration ChangeColumnToUser
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
# NULL
change_column :テーブル名, :カラム名, :型, null: true
# NOT NULL
change_column :テーブル名, :カラム名, :型, null: false
インデックス
change_column :テーブル名, :カラム名, :型, index: true
デフォルト
change_column :テーブル名, :カラム名, :型, default: "piyo"
すでに設定してあるデフォルト値を消す場合は change_column_default
を利用する。さらに false
を指定してしまいがちだが、 nil
にしないと Integer の場合は DEFAULT 0 になってしまい、意図したものと違うことがあるので注意が必要。
def up
change_column_default :テーブル名, :カラム名, nil
end
def down
change_column_default :テーブル名, :カラム名, 1
end
長さ
# varchar(12)
change_column :テーブル名, :カラム名, :string, limit: 12
コメント
Rails5からコメントを書けるようになった。
change_column :テーブル名, :カラム名, comment: "コメントです"
小数部の精度を指定する
MySQL5.6.4以降、datetime型で小数部(ミリ秒)の精度指定をサポートしている。Railsも合わせてミリ秒に対応させているので、基本的には指定したほうが良さげ。
def change
create_table :hoges do |t|
t.datetime :hoge_date, precision: 6
t.timestamps precision: 6
end
end
カラム名を変更する
rename_column :テーブル名, :変更前のカラム名, :変更後のカラム名
この時、対象のカラムにインデックスがある場合、そちらも自動的に変更してくれる。便利。
カラムを追加/削除する
piyoっていうstringなカラムを追加する。追加の場合は、作成時と同じでカラムを予め指定して作ることができる。
$ rails g migration AddColumnToUser piyo:string
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カラムにインデックス追加したり削除したり。複合ユニークだったり。
$ rails g migration AddIndexToUser
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モデルを複数所有するような感じ。