我想将用户表的某些列迁移到单独的相关表中。其中一些列使用ActiveRecord的serialize
功能将哈希值和数据集存储在一列中。
class User < ActiveRecord::Base
...
serialize :foo, Hash
...
end
我想将该列(除了许多其他列)移到一个单独的表中:
class Profile < ActiveRecord::Base
...
serialize :foo, Hash
belongs_to :user
...
end
作为迁移的一部分,我在删除用户列之前将一堆用户属性复制到配置文件中。问题是,当我读user.foo
时,数据不再反序列化。因此,当我设置profile.foo = user.foo
时,我收到错误:Attribute was supposed to be a Hash, but was a String
。
有没有办法在迁移过程中复制原始数据库值,还是在这种情况下是否需要执行自己的反序列化?
谢谢!
编辑:添加迁移
class CreateProfile < ActiveRecord::Migration
def up
create_table :profiles do |t|
t.integer :user_id
t.text :foo
# A bunch of other fields
end
User.all.find_each do |user|
params = { user: user }
# Copy all fields here
params[:foo] = user[:foo]
...
profile = Profile.new(params)
profile.save!
end
# Remove a bunch of fields
remove_column :users, :foo
...
end
...
end
答案 0 :(得分:2)
您可以在迁移中执行原始sql,如果您有大量用户记录,这将是最快的
execute("INSERT INTO profiles(user_id, foo) SELECT id, foo FROM users")
答案 1 :(得分:1)
您似乎要删除serialize :foo, Hash
模型中的User
行,预计此列将被删除。因此,您遇到了所描述的问题。你可以:
保留该行,并在所有迁移运行后稍后将其删除。这意味着 所有现有环境的所有迁移代码库(或者它们将在@scttnlsn指出后突破)。一个更简单的方法是......
使用SQL'UPDATE'语句复制数据:
假设您事先创建了个人资料,您可以像这样更新:
execute("UPDATE profiles SET foo = users.foo FROM users WHERE user_id = users.id")
如果您在此迁移过程中动态创建这些配置文件记录,请使用类似于@Vimsha建议的INSERT查询。