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.

Était-ce utile?

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 du up 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.

  1. Figure quelle partie de la migration jusqu'à travaillé. Commentaire sur les.
  2. Commentaire également / retirer de la partie de la migration qui a éclaté.
  3. 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.
  4. 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;.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top