2017-01-10 39 views
0

我有一個事件表和會話表。活動has_many會議,這是該協會。現在我想將會話表中的time_zone列僅移動到事件表中。那麼如何在遷移的幫助下做到這一點。如何將會話表中的time_zone現有記錄移至事件表中?在rails移植中更新數據列

回答

-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

首先,您需要確保與同一事件關聯的會話具有相同的時區。你可以這樣做:

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

這將返回一個哈希映射的event_id到與它相關聯的時區的數量。這個數字應該總是一個。其次,我建議您先添加events.time_zone,並在新代碼投入生產一段時間後開始使用它並刪除sessions.time_zone,並證明可以正常工作。

三,增加events.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 

注意,我在遷移重新定義模型。這是至關重要的,因爲:

  1. 原始模型可能有回調和驗證(當然,您可以跳過它們,但它是一個額外的預防措施,貢獻零值)。
  2. 如果您在路上6個月內移除模型,遷移將停止工作。

確定您的更改按預期工作後,您可以刪除sessions.time_zone。如果出現問題,您可以簡單地回滾上述遷移並輕鬆恢復工作版本。

+0

這工作。什麼情況下,不應該有任何方法可以恢復會話表中的time_zone? – Nikhil

+0

請注意,我沒有**刪除'sessions.time_zone'。查看最後一段 - 我建議你先遷移到新列,讓你的代碼使用它,一旦你確定它的工作原理刪除舊列。數據庫存儲很便宜,所以沒有急於求成。 –

+0

哦..我錯過了那部分..這有助於.. 它是有意義的創建第三個表來存儲像events_sessions表的關聯? – Nikhil