使用`update_all`时运行验证

时间:2016-09-22 16:46:53

标签: ruby-on-rails validation activerecord

根据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

1 个答案:

答案 0 :(得分:12)

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

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

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