2009-12-11 167 views
0

假设您有“lineitems”,并且您曾经从line_item定义“make”。在Rails迁移中迁移数据

最终你意识到make应该可以在自己的模型上,所以你创建了一个Make模型。

然后,您想要从line_items表中移除make列,但是要为每个line_item移除您想要find_or_create_by(line_item.make)的make。

我如何有效地在轨道迁移中做到这一点?我敢肯定,我可以为每个line_item运行一些简单的find_or_create_by,但我担心后备支持,所以我只是在这里发布此任何提示/建议/正确的方向。

谢谢!

回答

3

我想你应该检查Make.count是否等于在删除列之前的lineitems中的唯一总数,如果不是,则会引发错误。由于迁移是事务性的,如果它发生变化,模式不会改变,迁移也不会被标记为已执行。因此,您可以这样做:

class CreateMakesAndMigrateFromLineItems < ActiveRecord::Migration 
    def self.up 
    create_table :makes do |t| 
     t.string :name 
     … 
     t.timestamps 
    end 

    makes = LineItem.all.collect(:&make).uniq 
    makes.each { |make| Make.find_or_create_by_name make } 
    Make.count == makes.length ? remove_column(:line_items, :make) : raise "Boom!" 

    end 

    def self.down 
    # You'll want to put logic here to take you back to how things were before. Just in case! 
    drop_table :makes 
    add_column :line_items, :make 
    end 
end 
+0

事务性迁移仅在数据库供应商支持时才可用。 MySQL例如不提供事务性DDL,因此raise语句会导致迁移失败并使数据库处于不一致状态。 – Cluster 2013-03-06 10:39:35

+0

如果你添加了什么集群说,也许分成两个迁移,添加一个新的列,并做你需要做的任何事情。第二,当尘土已经沉淀,然后删除任何不再需要的列。这不是完美的,但会给你一个回头路。 – Ghoti 2013-07-31 09:23:23

0

您可以在迁移过程中放置​​常规ruby代码,以便您可以创建新表,在旧模型中运行一些代码将数据移动到新模型中,然后从原始模型中删除列。这甚至是可逆的,所以你的迁移仍然可以在两个方向上工作。

因此,针对您的情况,创建Make表并将make_id添加到lineitem。然后为每个订单项find_or_create添加lineitem上的make列,将返回的ID设置为lineitem上的新make_id。完成后,从lineitem表中删除旧的make列。