Help us understand the problem. What is going on with this article?

Railsのマイグレーション管理方法について

More than 1 year has passed since last update.

まえがき

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ファイル

db/migrate/20190813002037_create_users.rb
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

コマンドひとつで、マイグレーションファイルが出来上がります。
※コマンドを実行した後に、作成されたファイルを修正するでも構いません。

db/migrate/20190813002439_add_age_to_user.rb
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ファイルになり、管理がし易くなります。
 ※このテーブルを修正したい場合はこのファイル!といった管理がし易くなります。
デメリット:反映時に既存データが消えるため、必要なデータについては、一旦退避するなどの対応が必要です。
 ※既にリリースしたサービスであれば、データ損失にもつながるので、推奨しません。

既存マイグレーションファイルを直接修正します

db/migrate/20190813002037_create_users.rb
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構成を決めておけば、マイグレーションファイルの数を最小限に減らせると思いますが、
そんな簡単ではないですし、開発していくにつれ、「これもいる・これはいらない」というのがどうしても出てきてしまうと思います。
そのため、このような使い分けを私は使っています。

newburu
座右の銘は「晴笑雨笑」🔸駆け出しエンジニアさんの力になりたい。無料で楽しく!勉強/質問コミュニティを運用中(http://newburu.github.io)🔸自分のペースでゆっくりでも勉強したい方、ご連絡ください。ご協力します!
https://newburu.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away