所以我理解,通常数据迁移不是最佳实践,所以我很乐意实现rake任务。
我们之前有两个模型,User和Office没有正式的关系。用户所属的办公室被存储为仅具有办公室名称的字符串。为了查找我们必须使用的办公室:
Office.find_by_name(user.office)
这显然毫无意义,因此我尝试运行迁移来解决此问题。我正在添加字段" office_id"对用户,以便我们可以使用适当的belongs_to / has_one关系。
我希望确保将每个用户的办公室复制到新格式中,因此在这种情况下,我在模式迁移过程中使用数据迁移。我们还必须删除旧办公室"字段,否则它会干扰生成的belongs_to方法。
这就是我所拥有的:
if not column_exists? :users, :office_id
add_column :users, :office_id, :integer
if defined? User
User.all.each do |user|
results = ActiveRecord::Base.connection.execute("select office FROM users where id = #{user.id}")
office = Office.find_by_name(results.getvalue(0,0))
if office.present?
user.office_id = office.id
user.save!
end
end;nil
end
if column_exists? :users, :office
remove_column :users, :office
end
end
我必须使用
ActiveRecord::Base.connection.execute("select office FROM users where id = #{user.id}")
因为user.office正在从生成的belongs_to方法中提取,所以这确保我们从数据库中获取数据。
I saw this as one solution除了我不确定如何从办公室提取数据并使用sql将其设置为用户之外,它会清理代码的数量相当多。
答案 0 :(得分:0)
为什么你没有根据字符串列创建关系?
class User
belongs_to :office, foreign_key: :office_name, primary_key: :name
end
为了能够执行此操作,您应该将office
列重命名为其他内容,或者如果您不想重命名,则可以为您的关联选择其他名称并继续使用办公室列如此;
class User
belongs_to :user_office, foreign_key: :office, primary_key: :name
end
如果你想要移植数据,我建议你写一个rake任务,只运行一次,如下所示;
task set_users_office_id: :environment do
ActiveRecord::Base.connection.execute_sql(<<-SQL.squish)
UPDATE users
SET office_id = (SELECT id FROM offices WHERE offices.name = users.office)
SQL
end