まえがき
Railsのマイグレーション管理する方法についての個人的なめも。
賛否両論あると思いますが、まとめておきたいと思い、書いてます。
※誤記・不足あれば、ご支援いただけると助かります。
環境
Ruby 2.6.3
Rails 5.2.3
MySQL 5.7.25
状況
すでにモデルが一つ存在する状態での、カラム追加を想定しています。
◆Userモデル(Usersテーブル)
項目名 | DBカラム名 | 型 | 補足 |
---|---|---|---|
名前 | name | String |
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
◆Migrationファイル
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name
t.timestamps
end
end
end
この状態の時、以下のカラムを追加したい場合。
項目名 | DBカラム名 | 型 | 補足 |
---|---|---|---|
年齢 | age | Integer |
方法1:マイグレーションファイルを追加していく方法(推奨)
メリット:既存データへの影響を少なくしてDB構成を変更出来ます。
※既にリリースしたサービスであれば、これが有効
デメリット:変更があるたびにマイグレーションファイルが追加されるため、ファイルが多くなり管理が難しくなります。
※現在のDB状態を見るには、DBを直接確認するか、db/schema.rbを確認しましょう。
rails g migrateを使って、追加します
rails g migration AddAgeToUser age:integer
コマンドひとつで、マイグレーションファイルが出来上がります。
※コマンドを実行した後に、作成されたファイルを修正するでも構いません。
class AddAgeToUser < ActiveRecord::Migration[5.2]
def change
add_column :users, :age, :integer
end
end
rake db:migrateで、DBに反映します
$ rake db:migrate
== 20190813002439 AddAgeToUser: migrating =====================================
-- add_column(:users, :age, :integer)
-> 0.0376s
== 20190813002439 AddAgeToUser: migrated (0.0377s) ============================
ageが追加されました。
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
| age | int(11) | YES | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
方法2:既存マイグレーションファイルを修正する方法
メリット:マイグレーションファイルが1テーブル1ファイルになり、管理がし易くなります。
※このテーブルを修正したい場合はこのファイル!といった管理がし易くなります。
デメリット:反映時に既存データが消えるため、必要なデータについては、一旦退避するなどの対応が必要です。
※既にリリースしたサービスであれば、データ損失にもつながるので、推奨しません。
既存マイグレーションファイルを直接修正します
class CreateUsers < ActiveRecord::Migration[5.2]
def change
create_table :users do |t|
t.string :name
t.integer :age # ここを追加
t.timestamps
end
end
end
rake db:migrate:resetで、DBに反映します
$ rake db:migrate:reset
Dropped database 'migration_sample_development'
Dropped database 'migration_sample_test'
Created database 'migration_sample_development'
Created database 'migration_sample_test'
== 20190813002037 CreateUsers: migrating ======================================
-- create_table(:users)
-> 0.0160s
== 20190813002037 CreateUsers: migrated (0.0161s) =============================
ageが追加された状態で再作成されます。
mysql> desc users;
+------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+---------+----------------+
| id | bigint(20) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | YES | | NULL | |
| age | int(11) | YES | | NULL | |
| created_at | datetime | NO | | NULL | |
| updated_at | datetime | NO | | NULL | |
+------------+--------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
注意:
方法1と方法2では、ageの追加位置が違いますが、方法1でも追加位置を指定する事は可能です。
個人的な使い分け
最初のリリースまでは、方法2のパターンを使い、リリースした後からは方法1を使っています。
最初にきっちりDB構成を決めておけば、マイグレーションファイルの数を最小限に減らせると思いますが、
そんな簡単ではないですし、開発していくにつれ、「これもいる・これはいらない」というのがどうしても出てきてしまうと思います。
そのため、このような使い分けを私は使っています。