2011-02-12 19 views
20

मैं रेल में माइग्रेशन लिखने के तरीकों की तलाश कर रहा हूं जिन्हें बिना किसी विफलता के डेटाबेस के खिलाफ कई बार निष्पादित किया जा सकता है।रेल में सशर्त माइग्रेशन कैसे लिखें?

उदाहरण देना के लिए कहते हैं कि मैं इस प्रवास है:

class AddUrlToProfile < ActiveRecord::Migration 
    def self.up 
    add_column :profile, :url, :string 
    end 

    def self.down 
    remove_column :profile, :url 
    end 
end 

url स्तंभ पहले से ही Profile तालिका में मौजूद है (यदि schema.rb उदाहरण के लिए अप्रत्याशित रूप से संशोधित किया गया है), मेरे प्रवास कि कह असफल हो जायेगी यह एक डुप्लिकेट है!

तो इस माइग्रेशन को केवल तभी निष्पादित करना है जब इसे करना है?

धन्यवाद

उत्तर

46

आप कुछ इस तरह कर सकते हैं:

class AddUrlToProfile < ActiveRecord::Migration 
    def self.up 
    Profile.reset_column_information 
    add_column(:profile, :url, :string) unless Profile.column_names.include?('url') 

    end 

    def self.down 
    Profile.reset_column_information 
    remove_column(:profile, :url) if Profile.column_names.include?('url') 
    end 
end 

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

यदि आपके पास इसके लिए कई उपयोग के मामले हैं तो आप किसी फ़ंक्शन में कोड को कारगर बना सकते हैं और अपने माइग्रेशन में पुनः उपयोग कर सकते हैं।

+0

अच्छा समाधान! धन्यवाद! –

+2

एफवाईआई: आम तौर पर आपके माइग्रेशन में मॉडलों को संदर्भित करना एक बुरा विचार है - क्या भविष्य में उस मॉडल को हटा दिया गया है? या परिवर्तन? इसके बजाय, '' 'क्लास प्रोफाइल

8

यह

def self.table_exists?(name) 
    ActiveRecord::Base.connection.tables.include?(name) 
end 

if table_exists?(:profile) && !Profile.column_names.include?("url") 
    add_column :profile, :url, :string 
end 
+0

धन्यवाद फर्नांडो! –

15

रेल 3.X के लिए, वहाँ है column_exists?(:table_name, :column_name) विधि काम करना चाहिए।

रेल 2.X लिए, आप निम्न के साथ स्तंभों के अस्तित्व की जाँच कर सकते हैं:

ActiveRecord::Base.connection.columns("<table name>").index {|col| col.name == "<column name>"} 
:

columns("<table name>").index {|col| col.name == "<column name>"} 

... या यदि आप एक प्रवास फ़ाइल में नहीं कर रहे हैं

यदि यह शून्य लौटाता है, तो ऐसा कोई स्तंभ मौजूद नहीं है। अगर यह फिक्सनम देता है, तो कॉलम मौजूद है। स्वाभाविक रूप से, आप {...} के बीच अधिक चयनात्मक मापदंडों अगर आप सिर्फ अपने नाम से ज्यादा से एक कॉलम की पहचान करना चाहते डाल सकते हैं, उदाहरण के लिए:

{ |col| col.name == "foo" and col.sql_type == "tinyint(1)" and col.primary == nil } 
2

एक सशर्त मेरे लिए काम किया में मेरे प्रवास रैपिंग। रेल 4.x

class AddUrlToProfile < ActiveRecord::Migration 
    unless Profile.column_names.include?("url") 
    def self.up 
     add_column :profile, :url, :string 
    end 

    def self.down 
     remove_column :profile, :url 
    end 
    end 
end 
संबंधित मुद्दे