Redmineプラグインのマイグレーションを適用した環境でdb:setup, db:resetを実行してはいけない
確認したバージョン: Redmine 4.0.4, 3.4.11(たぶん他のバージョンでも起きる)
- Redmineプラグインのマイグレーションを適用済みの環境で
-
rails db:setup
やrails db:reset
を実行してしまうと -
rails redmine:plugins:migrate
を実行するとTable already exists
といったエラーが出て失敗するようになる。1
問題を起こさない方法
- 新しいDBにスキーマを適用したい場合には
rails db:migrate redmine:plugins:migrate
を実行する
- DBのスキーマを作り直したい場合には
rails db:migrate:reset redmine:plugins:migrate
を実行する2
問題が起きたあとの修正方法
-
rails db:migrate:reset redmine:plugins:migrate
でDBを作り直す
-
schema_migrations
テーブルをいじってプラグインのマイグレーションが適用されたことにする
- プラグインのマイグレーションで追加されたテーブルなどを手動で消す
rails db:migrate redmine:plugins:migrate
を実行するrails db:migrate:reset redmine:plugins:migrate
を実行する2
-
rails db:migrate:reset redmine:plugins:migrate
でDBを作り直す -
schema_migrations
テーブルをいじってプラグインのマイグレーションが適用されたことにする - プラグインのマイグレーションで追加されたテーブルなどを手動で消す
のどれかで直る。だいたい上のほうが簡単なはず。
原因
-
db:setup
やdb:reset
はdb/schema.rb
をソースにしてスキーマとマイグレーションの適用状況を復元する。
-
db/schema.rb
のスキーマ情報にはRedmine本体のほか、プラグインのマイグレーションの結果も保存されているので、プラグインが追加したテーブルなどは正しく復元される。
- しかしマイグレーションの適用状況はRedmine本体のものしか保存されていないので、プラグインのマイグレーションの適用情報は失われる。
- そのため、次に
redmine:plugins:migrate
を実行するとプラグインのマイグレーションが二重に適用されてしまう。
- マイグレーションの中でテーブルやカラムを追加していた場合、同名のテーブルなどがすでに存在するため、エラーが起きてマイグレーションが失敗する。
- 一方、
db:migrate:reset
はdb:migrate
でマイグレーションをひとつずつ実行していくので、schema_migrations
テーブルとスキーマの不整合が起きない。
用語メモ
-
db/schema.rb
: DBのスキーマ情報を保存したファイル3。
- (↓以下2つは確認してないけどたぶん合ってるはず)
- マイグレーションの実行が完了するたびに更新される。
- 最後に実行が完了したマイグレーションのバージョンを保持している。
-
schema_migrations
テーブル: どのマイグレーションを適用したかを記録しておくためのテーブル。
コードリーディングメモ
-
active_record/railties/databases.rake
db:setup
の定義
db:reset
の定義
db:migrate:reset
の定義
-
db:setup
, db:reset
はdb:schema:load
を呼び出し、そこからDatabaseTasks.load_schema
が呼び出される。
-
active_record/tasks/database_tasks.rb
-
load_schema
ではKernel.load
でdb/schema.rb
を実行している
-
active_record/schema.rb
-
db/schema.rb
で使われるSchema
クラスの定義
-
ActiveRecord::Schema.define
がそのままDBにスキーマを適用するメソッドとして定義されている
-
redmine/plugin.rb
-
record_version_state_after_migrating
を上書きして、schema_migrations
に保存するバージョン名の末尾にプラグインのIDを追加している。
再現コード
db:setup
やdb:reset
はdb/schema.rb
をソースにしてスキーマとマイグレーションの適用状況を復元する。
-
db/schema.rb
のスキーマ情報にはRedmine本体のほか、プラグインのマイグレーションの結果も保存されているので、プラグインが追加したテーブルなどは正しく復元される。 - しかしマイグレーションの適用状況はRedmine本体のものしか保存されていないので、プラグインのマイグレーションの適用情報は失われる。
redmine:plugins:migrate
を実行するとプラグインのマイグレーションが二重に適用されてしまう。
- マイグレーションの中でテーブルやカラムを追加していた場合、同名のテーブルなどがすでに存在するため、エラーが起きてマイグレーションが失敗する。
db:migrate:reset
はdb:migrate
でマイグレーションをひとつずつ実行していくので、schema_migrations
テーブルとスキーマの不整合が起きない。db/schema.rb
: DBのスキーマ情報を保存したファイル3。
- (↓以下2つは確認してないけどたぶん合ってるはず)
- マイグレーションの実行が完了するたびに更新される。
- 最後に実行が完了したマイグレーションのバージョンを保持している。
schema_migrations
テーブル: どのマイグレーションを適用したかを記録しておくためのテーブル。db:setup
の定義db:reset
の定義db:migrate:reset
の定義-
db:setup
,db:reset
はdb:schema:load
を呼び出し、そこからDatabaseTasks.load_schema
が呼び出される。
-
load_schema
ではKernel.load
でdb/schema.rb
を実行している
-
db/schema.rb
で使われるSchema
クラスの定義 -
ActiveRecord::Schema.define
がそのままDBにスキーマを適用するメソッドとして定義されている
-
record_version_state_after_migrating
を上書きして、schema_migrations
に保存するバージョン名の末尾にプラグインのIDを追加している。
再現確認用のリポジトリを作った。pushするたびにGitHub Actionsで
- 再現用のプラグインを用意する
- Redmineのソースをダウンロードして展開する
- プラグインと
database.yml
をRedmineのディレクトリに配置する -
rails db:create db:migrate redmine:plugins:migrate
を実行してからrails db:reset redmine:plugins:migrate
を実行してエラーメッセージを確認する
という感じのことをやっていて、不具合が再現したらコミットのステータスが緑になる。
-
プラグインのすべてのマイグレーションがロールバックせずに何度でも実行できるなら問題は起きないが、そういうケースはごくまれだと思う。 ↩
-
ActiveRecord::ProtectedEnvironmentError
が発生したらRails 5に入ったDB破壊系taskの防止処理について | 日々雑記などを参照。 ↩ -
設定によっては
db/schema.rb
ではなくdb/structure.sql
になる。 ↩
Author And Source
この問題について(Redmineプラグインのマイグレーションを適用した環境でdb:setup, db:resetを実行してはいけない), 我々は、より多くの情報をここで見つけました https://qiita.com/vzvu3k6k/items/85cb1d7b692f2ed18a02著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .