7

テーブルに列を追加するための移行を書いています。列の値は、2つの既存の列の値に依存します。これを行う最善の方法は何ですか? 現在、私はこれを持っていますが、グループテーブルが非常に大きくなる可能性があるため、これが最良の方法かどうかはわかりません。Railsの移行でデータベース列を追加し、別の列に基づいてデータを入力してください

をまたは移行には、おそらくこのようないくつかのSQLを行う必要があるだろう:

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Groups = Group.all.each do |g| 
     c = "red" if g.is_active && is_live 
     c = "green" if g.is_active 
     c = "orange" 
     g.update_attribute(:type, c) 
    end 
    end 

    def self.down 

    end 
end 
+0

アップダウンでは何もしなかったのはなぜですか? – Robert

+0

これはちょうど私がここで編集中に行ったタイプミスです;) – user1404536

答えて

1

私はあなたのActiveRecordモデルに

after_create 
# or 
after_save 

でこれを行うだろう

execute('update groups set color = <another column>') 

ガイドレール:

http://guides.rubyonrails.org/migrations.html#using-the-up-down-methods

+2

ありがとうございますが、カラムは既存のすべてのグループにあらかじめ入力しておく必要があります。これは新しく作成されたグループでのみ機能します。 – user1404536

2

私は非常に代わり合計3つのクエリを実行お勧めします。常にデータベースを活用し、アレイ内のアイテムの束をループする。私はこのようなものがうまくいくと思うだろう。

これを書くために、is_activeがフィールド1がアクティブなフィールドをチェックすると仮定します。私は生きても同じであると仮定します。

のRails 3のアプローチ

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.where(active: 1, live: 1).update_all(type: "red") 
    Group.where(active: 1, live: 0).update_all(type: "green") 
    Group.where(active: 0, live: 0).update_all(type: "orange") 
    end 
end 

update_all hereのドキュメントを参照してお気軽に。

のRails 2.xのアプローチ

class AddColorToGroup < ActiveRecord::Migration 
    def self.up 
    add_column :groups, :color, :string 
    Group.update_all("type = red", "active = 1 AND live = 1") 
    Group.update_all("type = red", "active = 1 AND live = 0") 
    Group.update_all("type = red", "active = 0 AND live = 0") 
    end 
end 

Rails 2 documentation

+0

:(私のアプリケーションはRails 3を使用していません!ありがとう! – user1404536

+0

応答がRails 2.x版を含むように更新されました – Robert

+0

これで問題は解決しますか? – Robert

12

それは、このようなあなたの移行から、あなたのモデルを参照するために、一般的に悪い考えです。問題は、マイグレーションが順番に実行され、データベースの状態が変わったときに変更されることですが、モデルのバージョンはまったく変更されません。移行が作成されたときに存在していたモデルが今後も移行コードと互換性があるという保証はありません。

たとえば、将来、is_activeまたはis_live属性の動作を変更すると、この移行が中断する可能性があります。この古い移行は、新しいモデルコードに対して最初に実行され、失敗する可能性があります。ここでの基本的な例では、それは切り取られないかもしれませんが、フィールドが追加され、検証が実行できない前に、これが展開時に私を焼いてしまいました(私はあなたのコードがバリデーションをスキップしていることを知っていますが、

私のお気に入りのソリューションは、この種の移行をすべてプレーンSQLで行うことです。既にそれを考慮しているようですので、私はあなたがすでに何をすべきかを知っていると仮定します。

もう1つの選択肢は、ビジネスロジックが曖昧で、Railsyをもっと見たい場合は、マイグレーションファイルにマイグレーションファイルが書かれているときに存在するモデルの基本バージョンをそのまま含めることです。たとえば、あなたが移行ファイルにこのクラスを置くことができます:

class Group < ActiveRecord::Base 
end 

あなたのケースでは、それだけでは、おそらくモデルが壊れないことを保証するのに十分です。 activeliveが現時点でテーブル内のブール値フィールドであると仮定すると(そして、このマイグレーションが将来実行されるたびに)、それ以上のコードは必要ありません。より複雑なビジネスロジックがある場合は、このマイグレーション固有のバージョンのモデルに組み込むことができます。

モデルから移行バージョンにメソッド全体をコピーすることも考えられます。それを行う場合は、将来変更される可能性がある場合は、そこからアプリ内の外部モデルやライブラリを参照しないでください。これには、宝石のAPIを壊す変更が非常に一般的であるため、宝石やコアクラスのRuby/Railsクラスも含まれます(私はあなたにRails 3.0,3.1、および3.2を見ています)。

0

同様の状況で私はadd_columnを使用して列を追加し、直接SQLを使用して列の値を更新しました。 Jim Stewart's answerのモデルではなく、直接SQLを使用しました。これは、モデルの現在の状態と、実行されている移行に基づく表の現在の状態に依存しないためです。

class AddColorToGroup < ActiveRecord::Migration 
    def up 
    add_column :groups, :color, :string 
    execute "update groups set color = case when is_active and is_live then 'red' when is_active then 'green' else 'orange' end" 
    end 

    def down 
    remove_column :groups, :color 
    end 
end 
関連する問題