एक विफल रेल प्रवास को वापस लाना


82

आप एक असफल रेल प्रवासन को कैसे वापस लाते हैं? मुझे उम्मीद है कि rake db:rollbackअसफल प्रवास को पूर्ववत कर देगा, लेकिन नहीं, यह पिछले माइग्रेशन (विफल माइग्रेशन माइनस एक) को वापस ले जाता है। और rake db:migrate:down VERSION=myfailedmigrationया तो काम नहीं करता है। मैं इसमें कुछ बार भाग चुका हूं और यह बहुत निराशाजनक है। इस समस्या का डुप्लिकेट करने के लिए मैंने एक सरल परीक्षण किया है:

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

परिणाम:

== सरलतम: माइग्रेट करना ============================================================== ========
- add_column (: संपत्ति, परीक्षण: पूर्णांक)
   -> 0.0932 से
- add_column (: संपत्ति, त्रुटि)
रेक का गर्भपात!
एक त्रुटि हुई है, बाद में सभी माइग्रेशन रद्द कर दिए गए हैं:

तर्कों की गलत संख्या (3 के लिए 2)

ठीक है, इसे वापस लाने की अनुमति देता है:

$ रेक डीबी: रोलबैक
== AddLevelsToRoles: reverting ================================================== ==
- remove_column (: भूमिकाएँ, स्तर)
   -> 0.0778s
== AddLevelsToRoles: वापस (0.0779s) ========================================

है ना? SimpleTest से पहले मेरा आखिरी प्रवास था, असफल प्रवास नहीं। (और, यह अच्छा होगा यदि माइग्रेशन आउटपुट में संस्करण संख्या शामिल है।)

तो असफल माइग्रेशन SimpleTest के लिए डाउन रन करने का प्रयास करें:

$ रेक डीबी: माइग्रेट: डाउन संस्करण = 20090326173033
$

कुछ भी नहीं होता है, और कोई आउटपुट भी नहीं। लेकिन शायद यह प्रवास को वैसे भी भागा? तो सिंपलटेस्ट माइग्रेशन में सिंटैक्स त्रुटि को ठीक करने देता है, और इसे फिर से चलाने का प्रयास करता है।

$ रेक डीबी: माइग्रेट: अप वर्सन = 20090326173033
== सरलतम: माइग्रेट करना ============================================================== ========
- add_column (: संपत्ति, परीक्षण: पूर्णांक)
रेक का गर्भपात!
मैसकल :: त्रुटि: डुप्लीकेट कॉलम नाम 'परीक्षण': अन्य तालिका `संपत्ति` जोड़ें `परीक्षण` इंट (11)

नहीं। स्पष्ट रूप से माइग्रेट: डाउन काम नहीं किया। यह विफल नहीं है, यह सिर्फ क्रियान्वित नहीं है।

मैन्युअल रूप से डेटाबेस में जाने और इसे हटाने के अलावा, और फिर परीक्षण चलाने के अलावा उस डुप्लिकेट तालिका से छुटकारा पाने का कोई तरीका नहीं है। वहाँ से एक बेहतर तरीका हो गया है।

जवाबों:


79

दुर्भाग्य से, आपको MySQL के लिए मैन्युअल रूप से विफल माइग्रेशन को साफ़ करना होगा। MySQL ट्रांसेक्शनल डेटाबेस परिभाषा परिवर्तनों का समर्थन नहीं करता है।

रेलगाड़ी 2.2 में PostgreSQL के लिए लेनदेन संबंधी माइग्रेशन शामिल हैं। रेलेक्स के लिए रेल 2.3 में ट्रांजेक्शनल माइग्रेशन शामिल हैं।

यह वास्तव में आपकी समस्या के लिए अभी आपकी मदद नहीं करता है, लेकिन अगर आपके पास भविष्य की परियोजनाओं पर डेटाबेस का विकल्प है, तो मैं एक को ट्रांजैक्शनल डीडीएल के लिए समर्थन के साथ उपयोग करने की सलाह देता हूं क्योंकि यह माइग्रेशन को अधिक सुखद बनाता है।

अपडेट - यह अभी भी 2017 में सच है, रेल्स 4.2.7 और MySQL 5.7 पर, एलेजांद्रो बबियो द्वारा एक अन्य जवाब में यहां रिपोर्ट किया गया है।


1
उत्कृष्ट धन्यवाद। मैं PGSQL के साथ नई परियोजनाएं कर रहा हूं, इसलिए यह जानना अच्छा है कि यह एक विकल्प है।
insane.dreamer 20

यह अभी भी सबसे अच्छा जवाब है, इसलिए यह इनाम इमो के योग्य है।
नथ्नवाड़ा

20

एक निर्दिष्ट संस्करण में जाने के लिए बस उपयोग करें:

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

लेकिन अगर कोई माइग्रेशन किसी भी तरह से विफल रहता है, तो आपको पहले इसे साफ करना होगा। एक तरीका यह होगा:

  • उस काम downके हिस्से को पूर्ववत करने के लिए प्रवास की विधि को संपादित करेंup
  • पूर्व स्थिति में वापस जाएं (जहां आपने शुरुआत की थी)
  • माइग्रेशन ठीक करें (अपने परिवर्तनों को पूर्ववत् करने सहित down)
  • पुनः प्रयास करें

धन्यवाद। हां, मुझे पता है कि मैं असफल प्रवास के लिए सभी तरह से फिर से माइग्रेट कर सकता हूं, लेकिन उन मामलों में जहां मुझे प्रवासन का लंबा इतिहास है, यह कभी-कभी समस्याग्रस्त हो सकता है। आदर्श रूप से उन्हें सभी ठीक
कामों

20

ठीक है, दोस्तों, यहाँ आप वास्तव में यह कैसे करते हैं। मुझे नहीं पता कि उपरोक्त उत्तर किस बारे में बात कर रहे हैं।

  1. चित्र देखें कि अप माइग्रेशन के किस भाग ने काम किया। उन लोगों को बाहर टिप्पणी करें।
  2. यह भी टिप्पणी करें कि विच्छेद के भाग को हटा दें / हटा दें।
  3. फिर से माइग्रेशन चलाएं। अब यह प्रवास के गैर-टूटे हुए हिस्सों को पूरा करेगा, पहले से ही किए गए हिस्सों को छोड़ देगा।
  4. चरण 1 में आपके द्वारा टिप्पणी की गई माइग्रेशन के बिट्स को रद्द करें।

यदि आप यह सत्यापित करना चाहते हैं कि आप इसे अभी प्राप्त कर चुके हैं, तो आप फिर से नीचे और ऊपर जा सकते हैं।


2
मैं बहुत कुछ समान करता हूं, लेकिन मैं चरण 2 को प्रतिस्थापित करता हूं, "प्रवास का वह भाग ठीक करें जो टूट गया।"
डॉन किर्कबी

2
आखिरी बिंदु पर जोर देते हुए वर्थ - रन bundle exec rake db:migrate:redo। यह एक कदम पीछे और एक कदम आगे जाएगा, जिससे आप यह सत्यापित कर सकते हैं कि आपका नवीनतम माइग्रेशन पूरे रास्ते चलता है। यह एक अच्छा अभ्यास है कभी भी आपको कुछ कोड अपडेट के साथ माइग्रेशन को धक्का देना होगा।
Mahemoff

12

मैं सहमत हूं कि आपको जब संभव हो तो PostgreSQL का उपयोग करना चाहिए। हालाँकि, जब आप MySQL के साथ फंस जाते हैं, तो आप पहले अपने परीक्षण डेटाबेस पर अपना माइग्रेशन आज़माकर इन समस्याओं से बच सकते हैं:

rake db:migrate RAILS_ENV=test

आप पिछली स्थिति में वापस आ सकते हैं और फिर से प्रयास कर सकते हैं

rake db:schema:load RAILS_ENV=test

उत्तर की तुलना में अधिक वर्कअराउंड, लेकिन यह एक अच्छा विचार है जो मेरे सामने पहले नहीं हुआ था।
एमिली

10

2015 में रेल्स 4.2.1 और MySQL 5.7 के साथ, एक असफल प्रवासन मानक रेक क्रियाओं के साथ तय नहीं किया जा सकता है जो रेल प्रदान करते हैं, जैसा कि 2009 में था।

MySql DDL प्रतिमाओं ( MySQL 5.7 मैनुअल पर ) के रोलबैक का समर्थन नहीं करता है । और रेल उसके साथ कुछ नहीं कर सकती।

इसके अलावा, हम जाँच सकते हैं कि रेल कैसे काम कर रहा है: कनेक्शन एडेप्टर कैसे प्रतिक्रिया करता है, इसके आधार पर माइग्रेशन को लेनदेन में लपेटा जाता है:supports_ddl_transactions? । रेल स्रोत (v 4.2.1) में इस कार्रवाई की खोज के बाद, मैंने पाया कि केवल Sqlite3 और PostgreSql लेनदेन का समर्थन करता है, और डिफ़ॉल्ट रूप से यह समर्थित नहीं है।

संपादित करें इस प्रकार मूल प्रश्न का वर्तमान उत्तर: एक असफल MySQL माइग्रेशन को मैन्युअल रूप से तय किया जाना चाहिए।


मैं इस उत्तर को बिल्कुल नहीं समझता: संस्करण संख्याओं को अपडेट करने के अलावा यह मूल स्वीकृत उत्तर के लिए कुछ नहीं जोड़ता है।
नथ्नवाड़ा

1
मूल प्रश्न के लिए बहुत सही है। एंड्रयू ग्रिम के लिए शुरू किए गए इनाम के लिए: "जानना चाहते हैं कि क्या स्थिति 2009 के मार्च में पूछे गए सवाल के बाद से बदल गई है।" यह एक वर्तमान उत्तर है और भविष्य में किसी भी परिवर्तन की जांच करने के लिए एक विधि देता है।
अलेजांद्रो बबियो

8

ऐसा करने का आसान तरीका यह है कि अपने सभी कार्यों को लेनदेन में लपेटें:

class WhateverMigration < ActiveRecord::Migration

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

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

end

जैसा कि ल्यूक फ्रेंकल ने उल्लेख किया है, "MySql [MyISAM तालिकाओं में] लेन-देन का समर्थन नहीं करता है" - यही कारण है कि आप सामान्य रूप से या विशेष रूप से कम से कम MyISAM से बचने पर विचार कर सकते हैं।

यदि आप MySQL के InnoDB का उपयोग कर रहे हैं, तो उपरोक्त ठीक काम करेगा। या तो ऊपर या नीचे की कोई भी त्रुटि समाप्त हो जाएगी।

बारे में पता होना कार्रवाई के कुछ प्रकार के लेन-देन के माध्यम से वापस नहीं लाई जा सकती है। आम तौर पर, तालिका में परिवर्तन (तालिका को छोड़ना, स्तंभों को हटाना या जोड़ना आदि) को वापस नहीं किया जा सकता है।


5
यह MyISAM या InnoDB का सवाल नहीं है। InnoDB लेनदेन का समर्थन करता है, लेकिन यह ट्रांसेक्शनल डेटाबेस परिभाषा (DDL) परिवर्तनों का समर्थन नहीं करता है। PostgreSQL में आप एक टेबल को गिरा सकते हैं और फिर उस बदलाव को वापस ला सकते हैं!
ल्यूक फ्रेंकल

1
ल्यूक सही है, mysql DDL परिवर्तनों पर लेनदेन का समर्थन नहीं करता है। मुझे अपने आप से क्लीन अप पर विचार करना होगा जैसे कि टेबल्स से कॉलम जोड़ना और हटाना।
लियोन गुआन


1

मेरा एक टाइपो था ("add_column" में):

स्व

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

समाप्त

स्व

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

समाप्त

और फिर आपकी समस्या (आंशिक रूप से असफल प्रवासन को पूर्ववत् नहीं कर सकती)। कुछ असफल गुगली के बाद मैंने इसे चलाया:

स्व

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

समाप्त

स्व

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

समाप्त

जैसा कि आप देख सकते हैं कि मैंने केवल सुधार लाइन को हाथ से जोड़ा है, और फिर इसे फिर से हटा दिया है, इससे पहले कि मैंने इसे चेक किया।


1

ऊपर दिए गए अलेजांद्रो बैबियो का उत्तर सबसे अच्छा वर्तमान उत्तर प्रदान करता है।

एक अतिरिक्त विवरण जो मैं जोड़ना चाहता हूं:

जब myfailedmigrationमाइग्रेशन विफल हो जाता है, तो इसे लागू नहीं माना जाता है, और इसे चलाकर सत्यापित किया जा सकता है rake db:migrate:status, जो निम्न के समान आउटपुट दिखाएगा:

$  rake db:migrate:status
database: sample_app_dev

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

add_column :assets, :test, :integerअसफल प्रवास पर निष्पादित होने के अवशिष्ट प्रभाव को डेटाबेस स्तर पर एक alter table assets drop column test;क्वेरी के साथ उलट करना होगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.