11

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

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
4

4 に答える 4

18

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

たとえば、将来、is_activeまたはis_live属性の動作を変更すると、この移行が失敗する可能性があります。この古い移行は、新しいモデルコードに対して最初に実行され、失敗する可能性があります。ここでの基本的な例では、うまくいかない可能性がありますが、フィールドが追加されて検証を実行できなかった前に、これはデプロイメントで私を焼き尽くしました(コードが検証をスキップしていることは知っていますが、一般的にこれは懸念事項です)。

これに対する私のお気に入りの解決策は、プレーンSQLを使用してこの種のすべての移行を行うことです。あなたはすでにそれを考慮しているように見えるので、私はあなたがそこで何をすべきかをすでに知っていると仮定します。

別のオプションは、いくつかの厄介なビジネスロジックがある場合、またはコードをよりRailsyに見せたい場合は、移行が移行ファイル自体に書き込まれるときに存在するモデルの基本バージョンを含めることです。たとえば、次のクラスを移行ファイルに入れることができます。

class Group < ActiveRecord::Base
end

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

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

于 2013-03-18T06:06:21.153 に答える
6

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

これを書く目的のために、is_active が 1 がアクティブなフィールド active をチェックすると仮定します。ライブも同じだと思います。

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 のドキュメントを自由に確認してください。

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 のドキュメント

于 2013-03-08T01:01:29.443 に答える
1

私はこれを

after_create
# or
after_save

ActiveRecord モデルで:

class Group < ActiveRecord::Base
  attr_accessor :color

  after_create :add_color

  private

  def add_color
    self.color = #the color (wherever you get it from)
  end

end

または移行では、おそらく次のような SQL を実行する必要があります。

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

Rails ガイドの例を次に示します。

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

于 2013-03-08T00:23:43.010 に答える