2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

migration を書き換えたのに反映されない…Rails × Docker × MySQL でハマった話

Posted at

はじめに

Rails で以下のような migration を書いたのに、

add_index :users, :reset_password_token, unique: true

なぜか UNIQUE 制約が効かない、
rails db:migrate:reset をしても直らない……。

本記事は、実際に自分がハマった事例をもとに、

なぜ unique が反映されなかったのか、

なぜ rollback / reset でもダメだったのか

正しい解決方法は何かを 時系列で整理します。

環境は以下です。

Rails 7

Docker Compose

MySQL

Sorcery(reset_password_token)

発生した問題

以下の migration を作成しました。

class SorceryResetPassword < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :reset_password_token, :string, default: nil
    add_column :users, :reset_password_token_expires_at, :datetime
    add_column :users, :reset_password_email_sent_at, :datetime
    add_column :users, :access_count_to_reset_password_page, :integer, default: 0

    add_index :users, :reset_password_token, unique: true
  end
end

しかし MySQL で確認すると、

SHOW INDEX FROM users;

Non_unique | 1

UNIQUE になっていない

最初に試したこと(失敗)
① rollback して migration ファイルを書き換える

rails db:rollback
add_index :users, :reset_password_token, unique: true

rails db:migrate

反映されない

② migrate:redo を実行
rails db:migrate:redo VERSION=xxxxxxxxxxxxxx

ログを見ると、

-- add_index(:users, :reset_password_token)

unique: true が反映されていない

③ rails db:migrate:reset を実行

rails db:migrate:reset

それでも UNIQUE にならない

##なぜ反映されなかったのか(原因)
原因① migration は「設定」ではなく「履歴」

Rails の migration は

「今こうしたい」という設定

ではなく

「過去に何をしたか」という履歴

一度実行された migration を 書き換えるのは非推奨。

原因② index は上書きされない

すでに 非 UNIQUE の index が存在

同名 index がある場合、Rails は作り直さない

unique: true は後付けできない

原因③ Docker の MySQL volume
「rails db:migrate:reset」は

DB を drop / create するだけ

Docker の volume は削除されない
**Docker の volume は「コンテナを消しても残るデータ置き場」**です。

そのため、DB が完全初期化されていないケースがある

正しい解決方法(結論)
✅ 新しい migration を作成する(ベストプラクティス)
rails g migration FixUniqueIndexOnResetPasswordToken

class FixUniqueIndexOnResetPasswordToken < ActiveRecord::Migration[7.0]
  def change
    remove_index :users, :reset_password_token
    add_index :users, :reset_password_token, unique: true
  end
end

その後、

rails db:migrate

でマイグレーションを適用

確認

SHOW INDEX FROM users;

Non_unique | 0

UNIQUE 制約が正しく反映されました

まとめ(学び)

migration は 書き換えない
変更したい場合は 新しい migration で表現する
index の unique 変更は
👉 remove_index → add_index
Docker 環境では volume の存在を意識する

おわりに

「rollback したのに反映されない」
「migrate:reset したのに直らない」

という状態は、Rails が悪いのではなく
migration の思想を誤解しているだけでした。
同じところでハマる人の助けになれば幸いです。

2
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?