2017-01-10 7 views
0

私はイベントテーブルとセッションテーブルを持っています。イベントhas_manyセッション、これは関連です。これで、セッションテーブルのtime_zoneカラムをイベントテーブルのみに移動したいと考えています。どうすれば移行の助けを借りてこれを行うのですか?セッションテーブルのtime_zoneの既存のレコードをイベントテーブルに移動するにはどうすればよいですか?列のデータを列の更新で更新する

答えて

-1

次の移行をそのまま使用することができます。

class Test < ActiveRecord::Migration 
    def change 
    add_column :events, :time_zone, :string 

    Event.all.each do |e| 
     e.update_attributes(time_zone: e.sessions.last.time_zone) 
    end 

    remove_column :sessions, :time_zone 
    end 
end 
+0

マイグレーション中にモデルを使用しないでください。コールバックや検証などをトリガすることができます。また、時間とともに変更できます(つまり、6か月間にモデルを削除すると移行が停止する)。 –

1

まず、同じイベントに関連付けられたセッションに同じタイムゾーンが設定されていることを確認する必要があります。これは、それに関連付けられたタイムゾーンの数にevent_idをマッピングするハッシュを返します

Session.group(:event_id).count(:time_zone) 

:あなたがこれを行うことができます。この番号は常に1でなければなりません。

第2に、新しいコードを本番環境にしばらくおいてから、別のマイグレーションでそれを使用してからsessions.time_zoneを削除してから削除することをお勧めします。私は、マイグレーションでモデルを再定義

class AddTimeZoneToEvents < ActiveRecord::Migration 
    class Event < ActiveRecord::Base; end 
    class Session < ActiveRecord::Base; end 

    def up 
    # Add a NULLable time_zone column to events. Even if the column should be 
    # non-NULLable, we first allow NULLs and will set the appropriate values 
    # in the next step. 
    add_column :events, :time_zone, :string 

    # Ensure the new column is visible. 
    Event.reset_column_information 

    # Iterate over events in batches. Use #update_columns to set the newly 
    # added time_zone without modifying updated_at. If you want to update 
    # updated_at you have at least two options: 
    # 
    # 1. Set it to the time at which the migration is run. In this case, just 
    #  replace #update_columns with #update! 
    # 2. Set it to the maximum of `events.updated_at` and 
    #  `sessions.updated_at`. 
    # 
    # Also, if your database is huge you may consider a different query to 
    # perform the update (it also depends on your database). 
    Event.find_each do |event| 
     session = Session.where(event_id: event.id).last 
     event.update_columns(time_zone: session.time_zone) 
    end 

    # If events don't always need to have time zone information then 
    # you can remove the line below. 
    change_column_null :events, :time_zone, false 
    end 

    def down 
    remove_column :events, :time_zone 
    end 
end 

注:

第三には、次のようになります。events.time_zoneを追加するための移行は(私は明確にするため、いくつかのコメントを追加しました)。

  1. 元のモデルでは、コールバックと検証が行われる可能性があります(ただし、スキップすることはできますが、ゼロ値に寄与する特別な予防策です)。
  2. 6か月以内にモデルを削除すると、移行が中断されます。

変更が正常に動作したら、sessions.time_zoneを削除してください。何かがうまくいかない場合は、上記の移行をロールバックして、簡単に作業バージョンを復元することができます。

+0

これは動作します。ダウンの場合は、セッションテーブルのtime_zoneを復元する方法はありませんか? – Nikhil

+0

私は** sessions.time_zoneを削除していないことに注意してください**。最後の段落を参照してください - 最初に新しい列に移行し、コードでそれを使用するようにして、それが機能することを確認したら古い列を削除することをお勧めします。データベースのストレージは安いので、急いではありません。 –

+0

ああ..私は..その部分を逃し、これは は、それが組合にevents_sessionsテーブルのようなものを保存するために3番目のテーブルを作成するために意味をなすだろう...その後に役立ちますか? – Nikhil