2017-01-10 42 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