【问题标题】:Running validations when using `update_all`使用 `update_all` 时运行验证
【发布时间】:2016-09-22 16:46:53
【问题描述】:

根据 Rails 文档 herehere,使用 update_all 不会执行以下操作 -

  • 它会跳过验证
  • 它不会更新updated_at 字段
  • 它会默默地忽略 :limit:order 方法

我正在尝试检查我的代码库并删除 update_all 的实例,尤其是因为第一点。

有没有办法仍然拥有update_all 的便利性并仍然运行验证?我知道我可以遍历每条记录并保存它,但这不仅在视觉上更混乱而且效率更低,因为它执行 N 条 SQL 语句而不是 1 条

# before
User.where(status: "active").update_all(status: "inactive")
# after
User.where(status: "active").each { |u| u.update(status: "inactive") }

谢谢!

编辑:我使用的是 Rails 4.2

【问题讨论】:

标签: ruby-on-rails validation activerecord


【解决方案1】:

不幸的是,update_all 速度更快,因为它不会为每条记录实例化一个活动记录对象,而是直接处理数据库。在您的情况下,由于您需要验证和回调,因此您需要实例化对象,因此您最好分批迭代 1000 个并按照最初显示的方式执行更新。如:

User.where(status: "active").find_each { |u| u.update(status: "inactive") }

find_each 方法一次只加载 1000 个对象,因此不会使垃圾收集器过载。如果您在数十万行中有批量记录,我会考虑返回 update_all 或将更新移至后台任务,因为部署时很容易导致超时。

【讨论】:

  • 为什么您使用数千个查询而不是单个查询?这仅仅是 Rubocop 错误的原因吗?
  • OP 由于验证需要循环,因此最好分批循环,GC 从过去的迭代中擦除内存中的对象,而不是一次将所有记录保存在内存中。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-18
  • 2016-08-04
  • 2013-05-23
  • 1970-01-01
  • 2018-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多