在Rails迁移中将一列更新为另一列的值

jrd*_*oko 69 migration activerecord timestamp ruby-on-rails

我在Rails应用程序中有一个包含数十万条记录的表,它们只有一个created_at时间戳.我正在添加编辑这些记录的功能,所以我想updated_at在表格中添加一个时间戳.在我的迁移中添加列,我想更新所有行以使新updated_at匹配旧created_at,因为这是Rails中新创建的行的默认值.我可以做一个find(:all)并遍历记录,但由于表的大小,这需要几个小时.我真正想做的是:

UPDATE table_name SET updated_at = created_at;
Run Code Online (Sandbox Code Playgroud)

在使用ActiveRecord而不是执行原始SQL的Rails迁移中有更好的方法吗?

nat*_*vda 119

我会创建一个迁移

rails g migration set_updated_at_values
Run Code Online (Sandbox Code Playgroud)

在里面写下这样的东西:

class SetUpdatedAt < ActiveRecord::Migration
  def self.up
    Yourmodel.update_all("updated_at=created_at")
  end

  def self.down
  end
end
Run Code Online (Sandbox Code Playgroud)

这样你就可以实现两件事

  • 这是一个可重复的过程,每个可能的部署(如果需要)都会被执行
  • 这很有效率.我想不出更多的rubyesque解决方案(效率很高).

注意:如果查询太难以使用activerecord写入,您还可以在迁移中运行原始sql.只需写下以下内容:

Yourmodel.connection.execute("update your_models set ... <complicated query> ...")
Run Code Online (Sandbox Code Playgroud)

  • `Yourmodel.update_all'update_at = created_at'`更好,不是吗?它也适用于范围. (40认同)

Gre*_*Dan 20

您可以使用与原始SQL非常相似的update_all.这就是你拥有的所有选择.

顺便说一句,我个人并不太关注迁移.有时原始SQL是最好的解决方案.通常,迁移代码不会被重用.这是一次性动作,所以我不打扰代码纯度.

  • `Yourmodel.update_all"updated_at = created_at"` (8认同)
  • 这取决于您的部署需求.我真的很喜欢使用迁移,因为它们允许在现有平台上重复部署并获得相同的结果.我们有几个阶段的部署:开发,测试,qa /验收,概念验证平台(用于测试客户端),生产平台:我们需要能够将现有数据迁移到新部署的版本而不会出现故障.在我们的示例中,添加列并确保数据正常不是一次性操作. (2认同)
  • 在迁移中声明模型通常是一个明智的想法,因为这可以防止稍后重新定义原始模型时出现问题。刚刚发现这篇文章很好地解释了一切:http://complicated-simplicity.com/2010/05/using-models-in-rails-migrations/ (2认同)

Mar*_*her 10

正如gregdan所写,你可以使用update_all.你可以这样做:

Model.where(...).update_all('updated_at = created_at')
Run Code Online (Sandbox Code Playgroud)

第一部分是您的典型条件.最后一部分说明如何进行分配.这将产生一个UPDATE声明,至少在Rails 4中.


Sar*_*mar 5

您可以直接运行以下命令到您的rails console ActiveRecord::Base.connection.execute("UPDATE TABLE_NAME SET COL2 = COL1")

例如:我想用项目表的remote_id 更新我的项目表的sku。命令如下:
ActiveRecord::Base.connection.execute("UPDATE items SET sku = remote_id")