0
0

[Ruby on Rails]既存のテーブルにカラムを追加するためのマイグレーションにえらい苦戦した話

Last updated at Posted at 2023-11-28

経緯

初任教育研修で、既存のタスク管理アプリに機能を追加する際に苦戦したときのメモです。
タスク管理アプリに、タスクの期限機能を追加開発する際に、既存のtasksテーブルにduedateカラムを追加しようとしていました。

db:migrateコマンドの実行

まずはTasksテーブルにduedateカラムを追加するためのマイグレーションファイルを作成するためにgenarateコマンドを実行します。

rails g migration AddDueDateToTasks duedate:datetime

これで自動的に以下のようなマイグレーションファイルができました

class AddDueDateToTasks < ActiveRecord::Migration[7.1]
  def change
    add_column :tasks, :duedate, :datetime
  end
end

マイグレーションファイルの編集の際に陥った勘違い

まず、自分が勘違いして書いた間違ったコードがこちら

class AddDueDateToTasks < ActiveRecord::Migration[7.1]
  def change
    add_column :tasks, :duedate, :datetime, null: false
  end
end

duedateのnull falseにしたいから、テーブル生成のときと同じ感覚でここに追記してそのままrails db:migrateを実行してエラーを連発していました。


私と同じ勘違いをしている方のために説明すると、このコマンドでは既存のデータにduedateカラムが追加された際に、それが空になってしまうので矛盾が生じていたというものでした。

そしてその理由がわからないままdb:rollbackとdb:migrateを繰り返して、DBをぐちゃぐちゃにして時間を溶かしていきました。。。。

もし同じように苦しんでいる方がいましたら(本番環境でなかったら)以下のコマンドを実行して次をお読みください。既存のデータが全部なくなるので注意。

rails db:reset

マイグレーションファイルの編集(正解)

私の場合の正解はこんな感じでした。

class AddDueDateToTasks < ActiveRecord::Migration[7.1]
  def up
    # 最初にduedateカラムをnull許容で追加する
    add_column :tasks, :duedate, :datetime, null: true

    # 既存のレコードに現在の時間を設定する
    execute "UPDATE tasks SET duedate = NOW()"

    # null: false制約を適用する
    change_column :tasks, :duedate, :datetime, null: false
  end

  def down
    remove_column :tasks, :duedate
  end
end

基本的に継続開発を考えた際にはupとdownで記載するべきと知りました。
参考にした記事
【Ruby on Rails】changeとup・downの使い分けについて

また、先ほどの勘違いから流れを修正しました。

  1. まずはnullを許容して新しくduedateというカラムを作成
  2. 既存のレコードに対してduedateを記載
  3. null falseを適用する

このように修正することで無事に

rails db:migrate

が実行できて既存のtasksテーブルにduedateカラムを追加することができました。

up.downで記載したからレビューを受けた後に楽に修正できた

追加機能を実装してレビューを受けたら
『カラム名をduedateからdue_dateに変更してください』
というレビューを受けました。


カラム名を変更するためにまた、マイグレーションファイルを作成するのかと思いましたが、downによりロールバック時の挙動を定めていたので、
rails db:rollback

としてから、
マイグレーションファイルをdue_dateに修正して、

class AddDueDateToTasks < ActiveRecord::Migration[7.1]
  def up
    add_column :tasks, :due_date, :datetime, null: true

    execute "UPDATE tasks SET due_date = NOW()"

    change_column :tasks, :due_date, :datetime, null: false
  end

  def down
    remove_column :tasks, :due_date
  end
end

もう一回rails db:migrateを実行するだけでテーブルの修正は完了できました。よかった。

まとめ

ということで機能追加のためにテーブルにカラムを追加することができました。誤っている部分がありましたらご指摘していただけると大変助かります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0