Pergunta

Como você reverter uma migração trilhos falhou? Eu esperaria que rake db:rollback iria desfazer a migração falhou, mas não, ele reverte a migração anterior (a não migração menos um). E rake db:migrate:down VERSION=myfailedmigration não quer trabalhar. Eu corri para isso algumas vezes e é muito frustrante. Aqui está um teste simples que fiz para duplicar o 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)

ok, deixa o rolo de volta:

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

hein? que foi a minha última migração antes SimpleTest, não houve falha na migração. (E oh, que seria bom se a saída de migração incluído o número da versão).

Então, vamos tentar executar o baixo para a migração falhou SimpleTest:

$ rake db:migrate:down VERSION=20090326173033
$

Nada acontece, e nenhuma saída também. Mas talvez ele correu a migração de qualquer maneira? Então vamos corrigir o erro de sintaxe na migração SimpleTest, e tentar executá-lo novamente.

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

Não. Obviamente, a migrar: baixo não funcionou. Não é não, ele simplesmente não está em execução.

Não há forma de se livrar do que a tabela duplicado que não vai manualmente no banco de dados e removê-lo e, em seguida, executar o teste. Tem que haver uma maneira melhor do que isso.

Foi útil?

Solução

Infelizmente, você deve limpar manualmente migrações falhadas para MySQL. O MySQL não suporta alterações de definição de banco de dados transacionais.

Rails 2.2 inclui migrações transacionais para PostgreSQL. Rails 2.3 inclui migrações transacionais para SQLite.

Isto não realmente ajudá-lo para o seu problema agora, mas se você tem uma escolha de banco de dados sobre projetos futuros, eu recomendo usar um com suporte para DDL transacional porque faz migrações muito mais agradável.

Atualização -. Isso ainda é verdade em 2017, on Rails 4.2.7 e MySQL 5.7, relatado por Alejandro Babio em outra resposta aqui

Outras dicas

Para ir para uma versão especificada apenas usar:

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

Mas se a migração falhar parte do caminho, você vai ter que limpá-lo primeiro. Uma forma seria:

  • editar o método down da migração para apenas desfazer a parte do up que trabalhou
  • voltar migrar para o estado anterior (onde começou)
  • corrigir a migração (incluindo desfazer as alterações ao down)
  • tente novamente

OK, pessoal, aqui é como você realmente fazê-lo. Eu não sei o que as respostas acima estão falando.

  1. descobrir qual parte da migração se trabalhou. Comentar os para fora.
  2. Também comente / remover a parte da migração que quebrou.
  3. Executar a migração novamente. Agora ele vai concluir as partes não quebrado da migração, ignorando as partes que já foram feitas.
  4. Uncomment os bits da migração você comentado na etapa 1.

Você pode migrar para baixo e back-up novamente se você quiser verificar se você tem isso agora.

Eu concordo que você deve usar o PostgreSQL, quando possível. No entanto, quando você está preso com o MySQL, você pode evitar a maioria destes problemas por tentar sua migração em seu banco de dados de teste em primeiro lugar:

rake db:migrate RAILS_ENV=test

Você pode reverter para o estado anterior e tente novamente com

rake db:schema:load RAILS_ENV=test

No 2015, com Rails 4.2.1 e MySQL 5.7, a migração falha não pode ser corrigido com ações de rake padrão que Rails fornecem, como era no de 2009.

MySql não suporta reversão de statments DDL (em MySQL 5.7 manual ). E Rails não pode fazer nada com isso.

Além disso, podemos verificar como Rails está fazendo o trabalho: A migração é envolto em uma transação dependendo de como adaptador de ligação responder a :supports_ddl_transactions?. Depois de uma busca dessa ação na fonte trilhos (v 4.2.1), descobri que só Sqlite3 e PostgreSQL transações suportes, e por padrão não é suportado.

Editar Assim, a resposta atual à pergunta inicial: A falha MySQL migração deve ser corrigido manualmente

.

A maneira fácil de fazer isso é envolver todas as suas ações em uma transação:

class WhateverMigration < ActiveRecord::Migration

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

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

end

Como Lucas Francl observou, "MySql [ 's tabelas MyISAM Não] operações de apoio" - é por isso que você pode considerar evitando MySQL, em geral, ou pelo menos MyISAM em particular

.

Se você estiver usando InnoDB do MySQL, então o acima vai funcionar muito bem. Quaisquer erros em cima ou para baixo vai recuar.

Esteja ciente alguns tipos de acções não podem ser revertidas através de transações. Geralmente, as mudanças de mesa (que deixam cair de uma mesa, remoção ou adição de colunas, etc.) não pode ser revertida.

Executar apenas a migração para baixo do console:

http: //gilesbowkett.blogspot .com / 2007/07 / how-to-use-as migrações-de-console.html (clicar para sua pastie)

Eu tinha um erro de digitação (em "add_column"):

def self.up

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

final

def self.down

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

final

e (migração não pode desfazer parcialmente falhou), então o seu problema. depois de algum falhou googling eu corri o seguinte:

def self.up

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

final

def self.down

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

final

como você pode ver eu apenas adicionei a linha correção à mão, e, em seguida, removido-lo novamente, antes que eu verifiquei em.

A resposta de Alejandro Babio acima fornece a melhor resposta atual.

Um detalhe adicional que deseja adicionar:

Quando a migração myfailedmigration falhar, ele não é considerado como aplicado, e isso pode ser verificada através da execução rake db:migrate:status, que iria mostrar uma saída semelhante à seguinte:

$  rake db:migrate:status
database: sample_app_dev

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

O efeito residual de add_column :assets, :test, :integer sendo executado sobre a migração não terá que ser revertido no nível de banco de dados com uma consulta alter table assets drop column test;.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top