run remove rails migrations index data create column mysql ruby-on-rails rails-activerecord rails-migrations

mysql - remove - rollback migration rails



Recuperar una migraciĆ³n fallida de Rails (9)

¿Cómo revierte una migración de rieles fallidos? Esperaría que rake db:rollback deshaga la migración fallida, pero no, revierte la migración anterior (la migración fallida menos uno). Y rake db:migrate:down VERSION=myfailedmigration tampoco funciona. Me he topado con esto algunas veces y es muy frustrante. Aquí hay una prueba simple que hice para duplicar el 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

resultado:

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

vale, vamos a enrollarlo de vuelta:

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

¿eh? esa fue mi última migración antes de SimpleTest, no la migración fallida. (Y ah, sería bueno si la salida de migración incluyera el número de versión).

Intentemos ejecutar el down para la migración fallida SimpleTest:

$ rake db:migrate:down VERSION=20090326173033 $

No pasa nada y tampoco hay salida. Pero tal vez se ejecutó la migración de todos modos? Entonces, solucionemos el error de sintaxis en la migración SimpleTest e intentemos ejecutarlo nuevamente.

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

Nop. Obviamente, la migración: hacia abajo no funcionó. No está fallando, simplemente no se está ejecutando.

No hay forma de deshacerse de esa tabla duplicada que no sea acceder manualmente a la base de datos y eliminarla, y luego ejecutar la prueba. Tiene que haber una mejor manera que eso.


Desafortunadamente, debe limpiar manualmente las migraciones fallidas para MySQL. MySQL no admite cambios en la definición de la base de datos transaccional.

Rails 2.2 incluye migraciones transaccionales para PostgreSQL. Rails 2.3 incluye migraciones transaccionales para SQLite.

Esto realmente no te ayuda para tu problema ahora, pero si tienes una opción de base de datos en proyectos futuros, te recomiendo usar uno con soporte para DDL transaccional porque hace que las migraciones sean mucho más agradables.

Actualización: esto sigue siendo cierto en 2017, en Rails 4.2.7 y MySQL 5.7, reportados por Alejandro Babio en otra respuesta aquí.



En 2015 con Rails 4.2.1 y MySQL 5.7, una migración fallida no se puede arreglar con las acciones de rake estándar que ofrece Rails, como lo fue en 2009.

MySql no admite la reversión de las sentencias DDL (en el manual de MySQL 5.7 ). Y Rails no puede hacer nada con eso.

Además, podemos verificar cómo Rails está haciendo el trabajo: una migración se envuelve en una transacción según cómo responda el adaptador de conexión :supports_ddl_transactions? . Después de buscar esta acción en rails source (v 4.2.1), descubrí que solo Sqlite3 y PostgreSql admiten transacciones y, por default no es compatible.

Edite la respuesta actual a la pregunta original: una migración de MySQL fallida se debe corregir manualmente.


Estoy de acuerdo en que debes usar PostgreSQL cuando sea posible. Sin embargo, cuando está atrapado con MySQL, puede evitar la mayoría de estos problemas probando primero su migración en su base de datos de prueba:

rake db:migrate RAILS_ENV=test

Puede volver al estado anterior y volver a intentar con

rake db:schema:load RAILS_ENV=test


La manera más fácil de hacerlo es ajustar todas sus acciones en una transacción:

class WhateverMigration < ActiveRecord::Migration def self.up ActiveRecord::Base.transaction do ... end end def self.down ActiveRecord::Base.transaction do ... end end end

Como señaló Luke Francl, "las tablas MyISAM de MySql no admiten transacciones", por lo que puede considerar evitar MySQL en general o al menos MyISAM en particular.

Si está utilizando InnoDB de MySQL, lo anterior funcionará perfectamente. Cualquier error en arriba o abajo retrocederá.

TEN EN CUENTA que algunos tipos de acciones no se pueden revertir a través de transacciones. Por lo general, los cambios en la tabla (descartar una tabla, eliminar o agregar columnas, etc.) no se pueden revertir.


La respuesta de Alejandro Babio arriba proporciona la mejor respuesta actual.

Un detalle adicional que quiero agregar:

Cuando la migración myfailedmigration falla, no se considera aplicada, y esto se puede verificar ejecutando el myfailedmigration rake db:migrate:status , que mostraría un resultado similar al siguiente:

$ rake db:migrate:status database: sample_app_dev Status Migration ID Migration Name -------------------------------------------------- up 20130206203115 Create users ... ... down 20150501173156 Test migration

El efecto residual de add_column :assets, :test, :integer está ejecutando en la migración fallida tendrá que invertirse en el nivel de la base de datos con una alter table assets drop column test; consulta.


OK, amigos, así es cómo lo hacen en realidad. No sé de qué están hablando las respuestas anteriores.

  1. Averigua qué parte de la migración ascendente funcionó. Comenta ésos.
  2. También comente / elimine la parte de la migración que se rompió.
  3. Ejecute la migración nuevamente. Ahora completará las partes no rotas de la migración, omitiendo las partes que ya se han realizado.
  4. Descomente los bits de la migración que comentó en el paso 1.

Puede migrar hacia abajo y hacia atrás otra vez si desea verificar que lo tiene ahora mismo.


Para ir a una versión especificada simplemente use:

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

Pero si una migración falla en parte, primero tendrá que limpiarla. Una forma sería:

  • edite el método down de la migración para deshacer la parte del up que funcionó
  • migrar de nuevo al estado anterior (donde comenzó)
  • corrige la migración (incluso deshacer los cambios en el down )
  • Inténtalo de nuevo

Tuve un error tipográfico (en "add_column"):

def self.up

add_column :medias, :title, :text add_colunm :medias, :enctype, :text

fin

def self.down

remove_column :medias, :title remove_column :medias, :enctype

fin

y luego su problema (no se puede deshacer parcialmente la migración fallida). después de algunos errores de Google, ejecuté esto:

def self.up

remove_column :medias, :title add_column :medias, :title, :text add_column :medias, :enctype, :text

fin

def self.down

remove_column :medias, :title remove_column :medias, :enctype

fin

como puedes ver, acabo de agregar la línea de corrección a mano, y luego la eliminé nuevamente, antes de registrarla.