Faire reculer la migration Rails a échoué
-
22-08-2019 - |
Question
Comment rouler en arrière une migration de rails a échoué? J'attendre à ce que rake db:rollback
déferait la migration a échoué, mais non, il annule la migration précédente (celle de moins de migration a échoué). Et rake db:migrate:down VERSION=myfailedmigration
ne fonctionne pas non plus. Je l'ai rencontré à quelques reprises et il est très frustrant. Voici un test simple, je fait de reproduire le problème:
class SimpleTest < ActiveRecord::Migration
def self.up
add_column :assets, :test, :integer
# the following syntax error will cause the migration to fail
add_column :asset, :test2, :integer
end
def self.down
remove_column :assets, :test
remove_column :assets, :test2
end
end
résultat:
== SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) -> 0.0932s -- add_column(:asset, :error) rake aborted! An error has occurred, all later migrations canceled: wrong number of arguments (2 for 3)
ok, permet de rouler en arrière:
$ rake db:rollback == AddLevelsToRoles: reverting =============================================== -- remove_column(:roles, :level) -> 0.0778s == AddLevelsToRoles: reverted (0.0779s) ======================================
hein? qui était ma dernière migration avant SimpleTest, pas la migration a échoué. (Et oh, ce serait bien si la sortie de migration inclus le numéro de version.)
permet donc essayer de lancer vers le bas pour le SimpleTest de migration a échoué:
$ rake db:migrate:down VERSION=20090326173033 $
Rien ne se passe, et pas de sortie non plus. Mais peut-être il a couru la migration de toute façon? permet donc de corriger l'erreur de syntaxe dans la migration SimpleTest, et essayer de l'exécuter à nouveau.
$ rake db:migrate:up VERSION=20090326173033 == SimpleTest: migrating ===================================================== -- add_column(:assets, :test, :integer) rake aborted! Mysql::Error: Duplicate column name 'test': ALTER TABLE `assets` ADD `test` int(11)
Non. Il est évident que la migration: vers le bas ne fonctionnait pas. Ce n'est pas défaut, il est tout simplement pas d'exécution.
Pas moyen de se débarrasser de cette table en double autre que d'aller manuellement dans la base de données et la suppression, puis l'exécution du test. Il doit y avoir une meilleure façon que cela.
La solution
Malheureusement, vous devez nettoyer manuellement les échecs de migration pour MySQL. MySQL ne supporte pas les changements de définition de base de données transactionnelle.
Rails 2.2 inclut les migrations transactionnelles pour PostgreSQL. Rails 2.3 inclut les migrations transactionnelles pour SQLite.
Cela ne, mais si vous avez vous aide pas vraiment à votre problème en ce moment un choix de base de données sur les projets à venir, je recommande d'utiliser un avec prise en charge des transactions DDL car elle rend les migrations beaucoup plus agréable.
Mise à jour - cela est encore vrai en 2017, on Rails 4.2.7 et MySQL 5.7, rapportés par Alejandro Babio dans une autre réponse ici
.Autres conseils
Pour accéder à une version spécifiée il suffit d'utiliser:
rake db:migrate VERSION=(the version you want to go to)
Mais si une migration échoue en partie, vous devrez nettoyer d'abord. Une façon serait:
- modifier la méthode de
down
de la migration pour annuler seulement la partie duup
qui a travaillé - migration de retour à l'état antérieur (où vous avez commencé)
- fixer la migration (y compris défaisant vos modifications au
down
) - essayez à nouveau
OK, les gars, voici comment vous faites réellement. Je ne sais pas ce que les réponses ci-dessus parlent.
- Figure quelle partie de la migration jusqu'à travaillé. Commentaire sur les.
- Commentaire également / retirer de la partie de la migration qui a éclaté.
- Exécuter à nouveau la migration. Maintenant, il complètera les parties non brisés de la migration, en sautant les parties qui ont déjà été faites.
- Uncomment les bits de la migration vous avez commenté dans l'étape 1.
Vous pouvez migrer vers le bas et sauvegarder à nouveau si vous voulez vérifier que vous l'avez en ce moment.
Je suis d'accord que vous devez utiliser PostgreSQL lorsque cela est possible. Toutefois, lorsque vous êtes coincé avec MySQL, vous pouvez éviter la plupart de ces problèmes en essayant votre migration sur votre base de données de premier test:
rake db:migrate RAILS_ENV=test
Vous pouvez revenir à l'état précédent et essayez à nouveau avec
rake db:schema:load RAILS_ENV=test
2015 avec Rails 4.2.1 et MySQL 5.7, une migration échoué ne peut pas être fixé par des actions de râteau standard qui Rails fournissent, comme il était à 2009.
MySql ne supporte pas rollback de statments (à DDL MySQL 5.7 Manuel ). Et Rails ne peuvent rien faire avec cela.
En outre, nous pouvons vérifier comment Rails fait le travail: Une migration est enveloppé dans une transaction en fonction de la réponse des adaptateur de connexion à :supports_ddl_transactions?
. Après une recherche de cette action à la source des rails (v 4.2.1), je trouve que seulement Sqlite3 et par défaut il n'est pas pris en charge.
Modifier Ainsi, la réponse actuelle à la question initiale. Une migration MySQL a échoué doit être corrigé manuellement
La façon facile de le faire est d'envelopper toutes vos actions dans une transaction:
class WhateverMigration < ActiveRecord::Migration
def self.up
ActiveRecord::Base.transaction do
...
end
end
def self.down
ActiveRecord::Base.transaction do
...
end
end
end
Comme Luc Francl a noté, « [MySql tableaux de l 'MyISAM ne] opérations de soutien. » - ce qui est la raison pour laquelle vous pourriez envisager d'éviter MySQL en général ou au moins MyISAM en particulier
Si vous utilisez InnoDB de MySQL, le ci-dessus fonctionnera très bien. Toute erreur dans le haut ou vers le bas arrière.
Rendez-vous compte certains types d'actions ne peuvent être reversées par les transactions. En général, les changements de table (suppression d'une table, la suppression ou l'ajout de colonnes, etc.) ne peuvent pas être annulées.
Exécuter simplement la migration vers le bas de la console:
http: //gilesbowkett.blogspot .com / 2007/07 / how-to-use-migrations-de-console.html (cliquer sur son pastie)
J'ai eu une faute de frappe (dans "add_column"):
def self.up
add_column :medias, :title, :text add_colunm :medias, :enctype, :text
end
def self.down
remove_column :medias, :title remove_column :medias, :enctype
end
et votre problème (ne peut pas annuler la migration en partie échoué). après quelques i échoué googler couru ceci:
def self.up
remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text
end
def self.down
remove_column :medias, :title remove_column :medias, :enctype
end
comme vous pouvez le voir, je viens d'ajouter la ligne de correction à la main, puis enlevé à nouveau, avant je l'ai vérifié dans.
La réponse de Alejandro Babio ci-dessus fournit la meilleure réponse actuelle.
Un détail supplémentaire Je veux ajouter:
Lorsque la migration myfailedmigration
échoue, il est pas considéré comme appliqué, et cela peut être vérifié en exécutant rake db:migrate:status
, qui montrerait une sortie similaire à ce qui suit:
$ rake db:migrate:status
database: sample_app_dev
Status Migration ID Migration Name
--------------------------------------------------
up 20130206203115 Create users
...
...
down 20150501173156 Test migration
L'effet résiduel de add_column :assets, :test, :integer
en cours d'exécution sur la migration a échoué devra être inversée au niveau de la base de données avec une requête alter table assets drop column test;
.