Rails 4:pk更改的迁移

时间:2015-03-26 16:28:52

标签: ruby-on-rails postgresql activerecord migration

好的,那么,当你尝试使用数据类型进行简单的迁移时,它就没什么大不了的了。

但是在某些情况下,当您需要使用正在运行的生产数据库更改主键的类型时。

这个大胆的陈述很重要,因为rails不会为你提供修改id的方法,用“woooah证明它是正确的,它可能会破坏你的数据完整性,所以可怕”。但是,嘿,我需要更改类型并重新填充所有密钥为了这种完整性

好的,现在你知道了介绍,让我们深入研究一些代码。

以下迁移为您提供了工作数据库,但您也可以删除已迁移的表,因为旧的表变为无用的垃圾。请记住,主题键现在是uuid,我们需要将其设为整数。

class RebuildOrdersIds < ActiveRecord::Migration
  def up
    remove_column :orders, :id
    [:order_transitions, :order_items, :addresses].each do |table|
      remove_column table, :order_id
      add_column table, :order_id, :integer
    end
    Order.connection.execute("CREATE SEQUENCE order_index_seq START 100000;")
    Order.connection.execute("ALTER TABLE orders ADD COLUMN id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('order_index_seq');")
  end
  def down
    remove_column :orders, :id
    Order.connection.execute("DROP SEQUENCE order_index_seq;")
    add_column :orders, :id, :uuid, default: 'uuid_generate_v4()'
    Order.connection.execute("ALTER TABLE orders ADD CONSTRAINT primakey PRIMARY KEY (id);")
    [:order_transitions, :order_items, :addresses].each do |table|
      remove_column table, :order_id
      add_column table, :order_id, :uuid
    end
  end
end

如您所见,它会删除旧的PK并创建不同数据类型的新列。

如果您需要保存数据库的完整性,可能需要执行类似的操作。

class RebuildOrdersIds < ActiveRecord::Migration
  def up
    #creating second temporary column for things. It might as well be new integer column.
    [:orders, :order_transitions,
      :order_items, :addresses].each do |table|
        add_column table, :old_order_id, :uuid
    end

    #mapping stuff together, setting either new values (start) or copying old ones
    mapping = {}
    start = 100000
    Order.all.each do |o|
      mapping[o] = {transitions: o.order_transitions,
                    items: o.order_items,
                    address: o.address}
    end
    mapping.each do |o|
      o[0].update_attribute(:old_order_id, o[0].id)
      o[1][:transitions].empty? || o[1][:transitions].each do |t|
        t.update_attribute(:old_order_id, o[0].id)
      end
      o[1][:items].empty? || o[1][:items].each do |i|
        i.update_attribute(:old_order_id, o[0].id)
      end
      o[1][:address].nil? || o[1][:address].update_attribute(:old_order_id, o[0].id)
      start += 1
    end

    #remove old columns, add some new
    remove_column :orders, :id
    [:order_transitions, :order_items, :addresses].each do |table|
      remove_column table, :order_id
      add_column table, :order_id, :integer
    end

    #making new column with counter with offset start
    Order.connection.execute("CREATE SEQUENCE order_index_seq START #{start};")
    Order.connection.execute("ALTER TABLE orders ADD COLUMN id INTEGER PRIMARY KEY NOT NULL DEFAULT nextval('order_index_seq');")
  end
end

因此,应该有一些代码可以填充“id”值。

麻烦的是,没有任何工作。 #update_attribute都没有 也不是#update_all 也不.id,.save

如何实现所需的结果?

0 个答案:

没有答案