2011-02-12 23 views
20

私は、データベースに何度も失敗することなく実行できる、レールへの移行を書く方法を模索しています。レールに条件付き移行を書き込む方法は?

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

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

(schema.rbは、例えば予期せず変更されている場合)url列がすでにProfileテーブルに存在している場合、私の移行がと言って失敗します。たとえば

は、私はこの移行を持っているとしましょうそれは重複です!

この移行を実行するにはどうすればよいですか?

おかげ

答えて

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 

それが始まる前に、これは、カラム情報をリセットします - Profileモデルから最新の列情報を持っていることを確認することを実際のテーブルそれが存在しない場合は、列を追加するだけです。ダウン機能でも同じことが起こりますが、カラムが存在する場合は削除されます。

ユースケースが複数ある場合は、コードを関数に組み込んで、マイグレーションでコードを再利用することができます。

+0

ニース解決!ありがとう! –

+2

FYI:マイグレーション中にモデルを明示的に参照することは、一般的には悪い考えです。または変更?その代わりに、 '' 'class Profile

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

Railsの3.Xについて、column_exists?(:table_name, :column_name)方法があります動作するはずです。

Railsの2.Xについては、次を持つ列の存在を確認することができます。

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

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

を...か、移行ファイルにはいないのであれば

nilを返すと、そのような列は存在しません。 Fixnumを返した場合、その列は存在します。あなただけの、その名以上で列を識別したい場合はもちろん、あなたが例えば、{...}間のより選択的なパラメータを置くことができます。

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

私のために働いた条件で私の移行をラッピング。 Railsの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 
関連する問題