涉及两个记录的Rails数据迁移

时间:2018-03-13 19:01:27

标签: ruby-on-rails data-migration belongs-to has-one

所以我理解,通常数据迁移不是最佳实践,所以我很乐意实现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将其设置为用户之外,它会清理代码的数量相当多。

1 个答案:

答案 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