Domanda

Come si tira indietro una migrazione rotaie fallito? Mi aspetterei che rake db:rollback sarebbe annullare la migrazione fallita, ma no, rotola di nuovo la migrazione precedente (la migrazione non riuscita meno uno). E rake db:migrate:down VERSION=myfailedmigration non funziona neanche. Ho incontrato un paio di volte ed è molto frustrante. Ecco un semplice test che ho fatto di riprodurre il problema:

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

Risultati:

==  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, consente di rollback:

$ rake db:rollback
==  AddLevelsToRoles: reverting ===============================================
-- remove_column(:roles, :level)
   -> 0.0778s
==  AddLevelsToRoles: reverted (0.0779s) ======================================

eh? che era la mia ultima migrazione prima SimpleTest, non la migrazione non riuscita. (E, oh, sarebbe bello se l'uscita di migrazione incluso il numero di versione).

Quindi, consente di provare a eseguire il basso per la SimpleTest migrazione non riuscita:

$ rake db:migrate:down VERSION=20090326173033
$

Non succede nulla, e nessuna uscita neanche. Ma forse si correva la migrazione in ogni caso? Quindi, consente di correggere l'errore di sintassi nella migrazione SimpleTest, e provare a eseguirlo nuovamente.

$ 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)

No. Ovviamente la migrazione: verso il basso non ha funzionato. Non è mancato, non è solo l'esecuzione.

Non c'è modo di sbarazzarsi di quella tabella duplicata altro che andare manualmente nel database e la rimozione, e quindi eseguire il test. Ci deve essere un modo migliore di questo.

È stato utile?

Soluzione

Purtroppo, è necessario pulire manualmente migrazioni falliti per MySQL. MySQL non supporta le modifiche transazionali di definizione del database.

Rails 2.2 include le migrazioni transazionali per PostgreSQL. Rails 2.3 include le migrazioni transazionali per SQLite.

Questo in realtà non si aiuta per il vostro problema in questo momento, ma se avete una scelta di database su progetti futuri, mi consiglia di utilizzare uno con il supporto per DDL transazionale perché rende le migrazioni molto più piacevole.

Aggiornamento - questo è ancora vero nel 2017, on Rails 4.2.7 e MySQL 5.7, riportate da Alejandro Babio in un'altra risposta qui

.

Altri suggerimenti

Per passare a una versione specificata basta usare:

rake db:migrate VERSION=(the version you want to go to)

Ma se una migrazione non riesce parzialmente, dovrete per ripulirlo prima. Un modo potrebbe essere:

  • modificare il metodo down della migrazione per annullare solo la parte del up che ha lavorato
  • migrare torna allo stato precedente (punto di partenza)
  • fissare la migrazione (compresi annullare le modifiche apportate al down)
  • riprovare

OK, gente, ecco come effettivamente farlo. Non so che cosa le risposte di cui sopra stanno parlando.

  1. Figura quale parte della migrazione verso lavorato. Commento quelli fuori.
  2. Commento anche fuori / rimuovere la parte della migrazione che ha rotto.
  3. Esegui nuovamente la migrazione. Ora si completerà le parti non-rotto della migrazione, saltando le parti che sono già state fatte.
  4. Decommentare i bit della migrazione si come commento al punto 1.

È possibile migrare verso il basso e il backup di nuovo se si desidera verificare che ce l'hai al momento.

Sono d'accordo che si dovrebbe usare PostgreSQL, quando possibile. Tuttavia, quando si è bloccato con MySQL, è possibile evitare la maggior parte di questi problemi, cercando la migrazione sul database di test prima:

rake db:migrate RAILS_ENV=test

È possibile ripristinare lo stato precedente e riprova con

rake db:schema:load RAILS_ENV=test

a 2015 con Rails 4.2.1 e MySQL 5.7, una migrazione fallito non può essere risolto con le azioni di spoglia standard che forniscono Rails, come era il 2009.

MySql non supporta il rollback di statments DDL (a MySQL 5.7 Manuale ). E Rails non possono fare nulla con questo.

Inoltre, siamo in grado di verificare come Rails sta facendo il lavoro: Una migrazione è avvolto in una transazione a seconda di come adattatore di collegamento rispondono al :supports_ddl_transactions?. Dopo una ricerca di questa azione a rotaie fonte (v 4.2.1), ho scoperto che solo Sqlite3 e PostgreSql supporta le transazioni, e da predefinito non è supportato.

Modifica Così la risposta corrente alla domanda iniziale:. Una migrazione MySQL fallito deve essere fissato manualmente

Il modo più semplice per farlo è quello di avvolgere tutte le azioni in una transazione:

class WhateverMigration < ActiveRecord::Migration

 def self.up
    ActiveRecord::Base.transaction do
...
    end
  end

  def self.down
    ActiveRecord::Base.transaction do
...
    end
  end

end

Come osservato Luke Francl, "MySQL [ 's tabelle MyISAM non] transazioni di supporto" -. Ed è per questo si potrebbe considerare evitando MySQL in generale o almeno MyISAM in particolare

Se stai usando InnoDB di MySQL, quindi quanto sopra funzionano bene. Eventuali errori in alto o in basso si marcia indietro.

essere consapevoli alcuni tipi di azioni non è possibile ripristinare tramite transazioni. Generalmente, tabella cambia (cadere un tavolo, rimozione o aggiunta di colonne, etc.) non possono essere annullate.

Esegui solo la migrazione verso il basso dalla console:

http: //gilesbowkett.blogspot .com / 2007/07 / how-to-use-migrazioni-da-console.html (clic per raggiungere il suo pastie)

Ho avuto un errore di battitura (in "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

e quindi il problema (non può annullare la migrazione in parte fallito). dopo un po 'fallito googling mi sono imbattuto in questo modo:

  

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

come potete vedere ho solo aggiunto la linea di correzione a mano, e poi rimosso di nuovo, prima del check in.

La risposta di Alejandro Babio sopra fornisce la migliore risposta corrente.

Un dettaglio ulteriore voglio aggiungere:

Quando la migrazione myfailedmigration fallisce, non è considerata come applicata, e questo può essere verificato eseguendo rake db:migrate:status, che mostrano output simile al seguente:

$  rake db:migrate:status
database: sample_app_dev

 Status   Migration ID    Migration Name
--------------------------------------------------
   up      20130206203115  Create users
   ...
   ...
   down    20150501173156  Test migration

L'effetto residuo di add_column :assets, :test, :integer in esecuzione sulla migrazione non riuscita dovrà essere invertita a livello di database con una query alter table assets drop column test;.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top