はじめに
先週からエンジニアとして働き始めました。
といってもずっとgitの使い方でつまづいていて何もしてないんですが....
マイグレーションに関して少し指摘を受けて忘れないように忘備録として残します。
自分は結構おっちょこちょいなのでうっかり大切なデータ消しちゃったとかやりそうなのでマイグレーションとかは特に気を付けなければ…
何か間違っている点やアドバイスなどがあればコメントしていただけるととても助かります。
マイグレーションファイルの作り方
マイグレーションファイルを作成するときはあんま何も考えず
とりあえず変更出来てればよいか…
位の考えだったのですが実際はそんなことはなく
rails db:migrate
rails db:rollback
が問題なく実行できることを確認する必要があるようです。
理由に関してはあんまりうまく理解できなかったのですが....
マイグレーションの流れ
マイグレーションの流れとしては
まず
rails db:migrate:status
で今の状況を確認します
そうするとこんな感じに履歴が見れます
database: tt_db
Status Migration ID Migration Name
--------------------------------------------------
up 20190224051828 Create users
up 20190224052935 Add address to users
up 20190224053300 Change address column
up 20190224054338 Add birthday not null
up 20190224055456 Add good to users
このupというのはmigrationされた状態ということ
今では5個のマイグレーションファイルがありすべてマイグレーションが実行されている状態であることが分かります。
そしてそれを確認したら次に
rails db
でデータベースにアクセスします。
そして
select * from schema_migrations;
を実行します
そうすると
tt_db=> select * from schema_migrations;
version
----------------
20190224051828
20190224052935
20190224053300
20190224054338
20190224055456
(5 rows)
こういった感じでマイグレーションファイル情報が出てきます。
これはrails db:migrate:statusで出てきたupの情報と一致しているはずです。
次に現在のテーブル定義を確認しておきます
tt_db=> \d users;
Table "public.users"
Column | Type | Collation | Nullable | Default
-----------------+-----------------------------+-----------+----------+-----------------------------------
id | bigint | | not null | nextval('users_id_seq'::regclass)
name | character varying | | |
email | character varying | | |
password | character varying | | |
created_at | timestamp without time zone | | not null |
updated_at | timestamp without time zone | | not null |
address | text | | |
birthday | date | | |
password_digest | character varying | | |
good | character varying | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
こんなかんじでpostgresqlの場合は\d テーブル名でテーブルの情報が確認できます。
そして次に\qでデータベースから離脱してマイグレーションファイルを作成していきます。
今回はheightという身長を保存するカラムを作成していきます。
その場合は
rails g migration add_height_to_users
これを実行
そうするとdb/migrate以下にマイグレーションファイルがこんな感じで作成されているはずです。
class AddHeightToUsers < ActiveRecord::Migration[5.2]
def change
end
end
ここに変更する内容を書いていきますがrails db:migrate rails db:rollbackを確実に実行できるようにしていくために
class AddHeightToUsers < ActiveRecord::Migration[5.2]
def up
add_column :users, :height, :string
end
def down
remove_column :users, :height
end
end
みたいにmigrateされるときとrollbackされるときの処理を別々に書いていきます。
rails db:migrateを実行する前に現在のマイグレーションファイルの状態をrails db:migrate:statusで確認します
そうすると
database: tt_db
Status Migration ID Migration Name
--------------------------------------------------
up 20190224051828 Create users
up 20190224052935 Add address to users
up 20190224053300 Change address column
up 20190224054338 Add birthday not null
up 20190224055456 Add good to users
down 20190224063318 Add height to users
こんな感じになっているはずです。
この最後のdownがいま作ったマイグレーションファイルです。
これを確認したらrails db:migrateを実行します
成功するのでrails dbでデータベースにアクセスして問題なく変わっているか確認します。
tt_db=> \d users;
Table "public.users"
Column | Type | Collation | Nullable | Default
-----------------+-----------------------------+-----------+----------+-----------------------------------
id | bigint | | not null | nextval('users_id_seq'::regclass)
name | character varying | | |
email | character varying | | |
password | character varying | | |
created_at | timestamp without time zone | | not null |
updated_at | timestamp without time zone | | not null |
address | text | | |
birthday | date | | |
password_digest | character varying | | |
good | character varying | | |
height | character varying | | |
Indexes:
"users_pkey" PRIMARY KEY, btree (id)
こんな感じで最後にheightカラムが作成されています。
ついでに
select * from schema_migrations;で問題なく情報が一つ増えていることを確認します。
tt_db=> select * from schema_migrations;
version
----------------
20190224051828
20190224052935
20190224053300
20190224054338
20190224055456
20190224063318
(6 rows)
マイグレーションを実行する前は5rowsだったので問題なくできています。
そしたらデータベースから離脱して
rails db:migrate:statusでupが6つになっていることを確認します。
database: tt_db
Status Migration ID Migration Name
--------------------------------------------------
up 20190224051828 Create users
up 20190224052935 Add address to users
up 20190224053300 Change address column
up 20190224054338 Add birthday not null
up 20190224055456 Add good to users
up 20190224063318 Add height to users
次にためしにデータを作成します。
irb(main):001:0> user = User.new
=> #<User id: nil, name: nil, email: nil, password: nil, created_at: nil, updated_at: nil, address: nil, birthday: nil, password_digest: nil, good: nil, height: nil>
irb(main):002:0> user.name = "pon"
=> "pon"
irb(main):003:0> user.email = "pon@gmail.com"
=> "pon@gmail.com"
irb(main):004:0> user.password ="pon"
=> "pon"
irb(main):005:0> user.height = "180cm"
=> "180cm"
irb(main):006:0> user.save
(0.2ms) BEGIN
User Create (0.7ms) INSERT INTO "users" ("name", "email", "password", "created_at", "updated_at", "height") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id" [["name", "pon"], ["email", "pon@gmail.com"], ["password", "pon"], ["created_at", "2019-02-24 06:45:18.618771"], ["updated_at", "2019-02-24 06:45:18.618771"], ["height", "180cm"]]
(7.5ms) COMMIT
=> true
irb(main):007:0>
rails dbでデータベースに接続してデータを確認すると
id | name | email | password | created_at | updated_at | address | birthday | password_digest | good | height
----+------+---------------+----------+----------------------------+----------------------------+---------+----------+-----------------+------+--------
3 | pon | pon@gmail.com | pon | 2019-02-24 06:45:18.618771 | 2019-02-24 06:45:18.618771 | | | | | 180cm
(1 row)
こんな感じで情報が出てきます。
ここまでしたら
rails db:rollbackで前の状態に戻します
== 20190224063318 AddHeightToUsers: reverting =================================
-- remove_column(:users, :height)
-> 0.0007s
== 20190224063318 AddHeightToUsers: reverted (0.0013s) ========================
問題なくrollbackできるはず
rails db:migrate:statusを確認
database: tt_db
Status Migration ID Migration Name
--------------------------------------------------
up 20190224051828 Create users
up 20190224052935 Add address to users
up 20190224053300 Change address column
up 20190224054338 Add birthday not null
up 20190224055456 Add good to users
down 20190224063318 Add height to users
一つdownになっているやつがいまrollbackしたものです。
ここでrails dbでデータベースにアクセスしてusersの情報をみてみると
tt_db=> select * from users;
id | name | email | password | created_at | updated_at | address | birthday | password_digest | good
----+------+---------------+----------+----------------------------+----------------------------+---------+----------+-----------------+------
3 | pon | pon@gmail.com | pon | 2019-02-24 06:45:18.618771 | 2019-02-24 06:45:18.618771 | | | |
(1 row)
heightのカラムがなくなっています。
ここまでは良いのですがこのあとまたrails db:migrateを実行すると
tt_db=> select * from users;
id | name | email | password | created_at | updated_at | address | birthday | password_digest | good | height
----+------+---------------+----------+----------------------------+----------------------------+---------+----------+-----------------+------+--------
3 | pon | pon@gmail.com | pon | 2019-02-24 06:45:18.618771 | 2019-02-24 06:45:18.618771 | | | | |
(1 row)
こんな感じでheightの情報が消えています。
こんな感じでカラムが一度消えてしまうと情報も消えてしまいます。
これはカラムの内容を変更するときに特に気を付けなくてはいけないです。
emailというカラムをmailというカラムに変更したい場合に
rails g migration change_users_email_to_mail
として
class ChangeUsersEmailToMail < ActiveRecord::Migration[5.2]
def up
remove_column :users, :email
add_column :users, :mail, :string
end
def down
remove_column :users, :mail
add_column :users, :email, :string
end
end
としてmigrate rollbackが通るようにして
rails db:migrate:statusで現在の状況を確認して追加しようとしているのがdownとして問題なく入っているのを確認して
rails db:migrateを実行すると
usersテーブルの中身は
tt_db=> select * from users;
id | name | password | created_at | updated_at | address | birthday | password_digest | good | height | mail
----+------+----------+----------------------------+----------------------------+---------+----------+-----------------+------+--------+------
3 | pon | pon | 2019-02-24 06:45:18.618771 | 2019-02-24 06:45:18.618771 | | | | | |
(1 row)
こんな感じでmailの中身が消えた状態になってしまっています。
これが本番の環境で大切な情報が消えてしまったとなったら大変です....
なので気を付けるようにしましょう。
追記
カラム名の変更であれば
rename_columnをつかえるっぽいです。
なのでrename_columnを使えばデータは消えずに問題ないですがカラムの型を変更する場合はどうしたらよいかわからないです。
ちなみに
既にデプロイしているプロジェクトの大切な情報を含んでいるカラムを変更したい場合どうしたらよいのでしょうか?
わかる方教えてください( ;∀;)