Başarısız bir Rails geçişini geri alma


82

Başarısız bir ray geçişini nasıl geri alırsınız? Bunun rake db:rollbackbaşarısız geçişi geri almasını beklerdim , ancak hayır, önceki geçişi geri alır (başarısız geçiş eksi bir). Ve rake db:migrate:down VERSION=myfailedmigrationçalışmıyor da. Bununla birkaç kez karşılaştım ve bu çok sinir bozucu. İşte sorunu tekrarlamak için yaptığım basit bir test:

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

sonuç:

== SimpleTest: geçiş =============================================== ========
- add_column (: varlıklar,: test,: tamsayı)
   -> 0,0932
- add_column (: varlık,: hata)
tırmık iptal edildi!
Bir hata oluştu, sonraki tüm geçişler iptal edildi:

yanlış sayıda bağımsız değişken (3 için 2)

tamam, geri alalım:

$ rake db: geri alma
== AddLevelsToRoles: ters çevirme ============================================= ==
- remove_column (: roller,: düzey)
   -> 0,0778 sn
== AddLevelsToRoles: geri çevrildi (0.0779s) ======================================

ha? bu, başarısız geçiş değil, SimpleTest'ten önceki son geçişimdi. (Ve ah, taşıma çıktısının sürüm numarasını içermesi güzel olurdu.)

Öyleyse, başarısız geçiş SimpleTest'i aşağı çalıştırmayı deneyelim:

$ rake db: geçiş: aşağı VERSION = 20090326173033
$

Hiçbir şey olmuyor ve çıktı da yok. Ama belki yine de göçü yönetti? Öyleyse SimpleTest geçişinde sözdizimi hatasını düzeltelim ve tekrar çalıştırmayı deneyelim.

$ rake db: geçiş: yukarı VERSION = 20090326173033
== SimpleTest: geçiş =============================================== ========
- add_column (: varlıklar,: test,: tamsayı)
tırmık iptal edildi!
Mysql :: Hata: Yinelenen sütun adı 'test': ALTER TABLE `assets` ADD` test` int (11)

Hayır! Açıkçası göç: aşağı işe yaramadı. Başarısız değil, sadece icra etmiyor.

Bu yinelenen tablodan kurtulmanın, veritabanına manuel olarak girip onu kaldırıp ardından testi çalıştırmaktan başka yolu yoktur. Bundan daha iyi bir yolu olmalı.

Yanıtlar:


79

Maalesef MySQL için başarısız geçişleri manuel olarak temizlemelisiniz. MySQL, işlemsel veritabanı tanım değişikliklerini desteklemez.

Rails 2.2, PostgreSQL için işlem geçişlerini içerir. Rails 2.3, SQLite için işlem geçişlerini içerir.

Bu, şu anda sorununuz için size gerçekten yardımcı olmuyor, ancak gelecekteki projeler için bir veritabanı seçeneğiniz varsa, işlemsel DDL desteği olan birini kullanmanızı öneririm çünkü bu, geçişleri çok daha keyifli hale getirir.

Güncelleme - Bu, Alejandro Babio tarafından burada başka bir cevapta bildirilen Rails 4.2.7 ve MySQL 5.7'de 2017'de hala geçerlidir.


1
Mükemmel, teşekkürler. PGSQL ile yeni projeler yapacağım, bu yüzden bunun bir seçenek olduğunu bilmek güzel.
insane.dreamer

Bu hala en iyi cevap, bu yüzden bu ödül imho'yu hak ediyor.
nathanvda

20

Belirli bir sürüme gitmek için şunu kullanın:

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

Ancak bir taşıma kısmen başarısız olursa, önce onu temizlemeniz gerekir. Bunun bir yolu şudur:

  • downsadece upişe yarayan kısmını geri almak için geçiş yöntemini düzenleyin
  • önceki duruma (başladığınız yere) geri dönün
  • geçişi düzeltin (değişikliklerinizi geri almak dahil down)
  • Tekrar deneyin

Teşekkürler. Evet, başarısız geçişe kadar tüm yolu yeniden taşıyabileceğimi biliyorum, ancak uzun bir göç geçmişine sahip olduğum durumlarda bu bazen sorunlu olabilir. İdeal olarak her şeyi gayet iyi yürütmeleri gerekir, ancak çoğu zaman kısmen başarısız olmalarına neden oldum ve sonra daha büyük bir karmaşa var :-)
deli. Dreamer

20

Tamam millet, işte gerçekte nasıl yapacağınız. Yukarıdaki cevapların neden bahsettiğini bilmiyorum.

  1. Yukarı geçişin hangi kısmının işe yaradığını belirleyin. Bunları yorumlayın.
  2. Ayrıca geçişin kırılan kısmını yorumlayın / kaldırın.
  3. Taşıma işlemini tekrar çalıştırın. Şimdi, daha önce yapılmış kısımları atlayarak geçişin kırılmamış kısımlarını tamamlayacak.
  4. 1. adımda yorumladığınız geçişin parçalarını kaldırın.

Şu anda sahip olduğunuzu doğrulamak istiyorsanız, aşağı ve yukarı geçiş yapabilirsiniz.


2
Çok benzer bir şey yapıyorum, ancak 2. adımı "geçişin kesintiye uğrayan kısmını düzeltin" ile değiştiriyorum.
Don Kirkby

2
Son noktayı vurgulamaya değer - çalıştırın bundle exec rake db:migrate:redo. Bir adım geri ve bir adım ileri gidecek, böylece en son taşıma işleminizin baştan sona çalıştığını doğrulayabilirsiniz. Bu, bazı kod güncellemeleriyle birlikte bir geçişi zorlamanız gerektiğinde her zaman iyi bir uygulamadır.
mahemoff

12

Mümkün olduğunda PostgreSQL kullanmanız gerektiğini kabul ediyorum. Bununla birlikte, MySQL ile sıkışıp kaldığınızda, öncelikle test veritabanınızda geçişinizi deneyerek bu sorunların çoğundan kaçınabilirsiniz:

rake db:migrate RAILS_ENV=test

Önceki duruma dönebilir ve ile tekrar deneyebilirsiniz.

rake db:schema:load RAILS_ENV=test

Bir cevaptan çok geçici bir çözüm ama bu daha önce aklıma gelmemiş iyi bir fikir.
Emily

10

Rails 4.2.1 ve MySQL 5.7 ile 2015'te, başarısız bir geçiş, 2009'da olduğu gibi Rails'in sağladığı standart komisyon eylemleriyle düzeltilemez.

MySql, DDL ifadelerinin geri alınmasını desteklemez ( MySQL 5.7 Kılavuzunda ). Ve Rails bununla hiçbir şey yapamaz.

Ayrıca, Rails'in işi nasıl yaptığını kontrol edebiliriz: Bir geçiş, bağlantı adaptörünün nasıl yanıt verdiğine bağlı olarak bir işleme sarılır:supports_ddl_transactions? . Bu eylemi rails kaynağında (v 4.2.1) aradıktan sonra , yalnızca Sqlite3 ve PostgreSql'in işlemleri desteklediğini ve varsayılan olarak desteklenmediğini gördüm .

Düzenle Bu nedenle, orijinal sorunun şu anki yanıtı: Başarısız bir MySQL geçişi manuel olarak düzeltilmelidir.


Bu yanıtı tam olarak anlamıyorum: sürüm numaralarını güncellemenin dışında, kabul edilen orijinal cevaba hiçbir şey eklemiyor.
nathanvda

1
Orijinal soru için çok doğru. Ödül için Andrew Grimm için başladı: "Sorunun Mart 2009'da sorulmasından bu yana durumun değişip değişmediğini bilmek istiyorum." Bu güncel bir cevap ve gelecekte herhangi bir değişikliği kontrol etmek için bir yöntem sunuyor.
Alejandro Babio

8

Bunu yapmanın kolay yolu, tüm eylemlerinizi bir işlemde toplamaktır:

class WhateverMigration < ActiveRecord::Migration

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

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

end

Luke Francl'in belirttiği gibi, "MySql [MyISAM tabloları] işlemleri desteklemiyor" - bu yüzden genel olarak MySQL'den veya en azından MyISAM'den kaçınmayı düşünebilirsiniz.

MySQL'in InnoDB'sini kullanıyorsanız, yukarıdakiler gayet iyi çalışacaktır. Yukarı veya aşağı yönündeki tüm hatalar geri alınacaktır.

FARKINDA OLUN, bazı eylem türleri işlemler yoluyla geri alınamaz. Genel olarak, tablo değişiklikleri (bir tabloyu düşürmek, sütun kaldırmak veya eklemek, vb.) Geri alınamaz.


5
MyISAM veya InnoDB meselesi değil. InnoDB işlemleri destekler ancak işlemsel veritabanı tanımı (DDL) değişikliklerini desteklemez. PostgreSQL'de bir tabloyu bırakabilir ve ardından bu değişikliği geri alabilirsiniz!
Luke Francl

1
Luke haklı, mysql DDL değişikliklerinde işlemi desteklemiyor. Tablolardan sütun eklemek ve kaldırmak gibi temizlemeyi kendim düşünmem gerekiyor.
Leon Guan


1

Bir yazım hatası yaptım ("add_column" içinde):

def self.up

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

son

def self.down

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

son

ve sonra sorununuz (kısmen başarısız olan geçiş geri alınamaz). Bazı başarısız Google'lardan sonra bunu çalıştırdım:

def self.up

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

son

def self.down

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

son

Gördüğünüz gibi düzeltme satırını elle ekledim ve kontrol etmeden önce tekrar kaldırdım.


1

Alejandro Babio'nun yukarıdaki cevabı mevcut en iyi cevabı sağlıyor.

Eklemek istediğim bir ayrıntı daha:

Ne zaman myfailedmigrationgöç başarısız uygulanan bu kabul edilmez ve bu çalıştırarak doğrulanabilir rake db:migrate:statusaşağıdakine benzer çıkış gösteren bir iki bölümlü,:

$  rake db:migrate:status
database: sample_app_dev

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

Yürütülmenin add_column :assets, :test, :integerbaşarısız geçiş üzerindeki artık etkisi , veritabanı düzeyinde bir alter table assets drop column test;sorgu ile tersine çevrilmelidir .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.