【问题标题】:How to update all when you need callbacks fired?当您需要触发回调时如何更新所有内容?
【发布时间】:2011-08-03 19:02:43
【问题描述】:

假设我在一个名为 user_ids 的数组中有 15 个用户 ID。

如果我想把他们所有的名字都改成“Bob”,我可以这样做:

users = User.find(user_ids)
users.update_all( :name => 'Bob' )

不过,这不会触发回调。如果我需要在保存这些记录时触发回调,据我所知,唯一的方法是使用:

users = User.find(user_ids)
users.each do |u|
  u.name = 'Bob'
  u.save
end

然而,这可能意味着控制器操作中的任务运行时间很长。

所以,我的问题是,是否有任何其他更好/更高性能/更高效的方法来触发对一组记录的批量更新,确实触发记录上的回调?

【问题讨论】:

  • 也许您也可以列出有关您的问题的更多详细信息,因为有时此类问题有常见的解决方法
  • 嗯,特别是在我正在处理的模型中,我有渐进式验证,我使用 before_save 回调来验证是否存在某些信息,并基于模型设置“状态”字段关于信息是完整还是不完整。
  • 这显示了哪些方法调用回调等。davidverhasselt.com/set-attributes-in-activerecord

标签: ruby-on-rails ruby-on-rails-3 activerecord callback update-all


【解决方案1】:

不要使用each/find_each,而是尝试使用update 方法:

models.update(column: value)

这只是以下内容的包装:

models.each{|x| x.update(column: value)}

【讨论】:

  • 仅适用于 Rails 5。
  • 到目前为止,这应该是答案。
  • @Quv 不,这不应该。在这种情况下,Relation#update 只是 each + update 的包装。 @iafonov 的解释仍然成立。
【解决方案2】:

不,要运行回调,您必须实例化一个昂贵的操作对象。我认为解决您的问题的唯一方法是将您在回调中执行的操作重构为单独的方法,该方法可以使用 select_all 方法检索到的数据而无需对象实例化。

【讨论】:

【解决方案3】:

这是触发回调的另一种方式。而不是使用

models.update_all(params)

你可以使用

models.find_each { |m| m.update_attributes(params) }

不过,如果您要处理大量数据,我不推荐这种方法。
希望对您有所帮助!

【讨论】:

  • 这和update_all 不一样。 map 将为您的每个模型实例化一个 Ruby 对象,并为您的每个模型发出单独的 SQL 查询。 update_all 会将所有内容捆绑到一个 SQL 查询中,并且不会实例化对象 - 这就是为什么它对于大型集合要快得多。但是就像提到的@iafonov 的回答一样,您无法同时获得update_all 的速度和回调,因为根据定义,您不能在不实例化模型的情况下调用回调。
  • 虽然值得注意的是,如果您确实使用这样的方法,使用find_each 可能比使用map 或each 更好。
  • @GeorgeMillo 我不确定我是否理解您的第一条评论。你说“你不能在不实例化模型的情况下调用回调”,这正是map 所做的。当然,这只是一种变通方法,不建议用于性能很关键的大型数据库。只是回答OP的问题:)。现在,您可以使用find_each 发布此代码的示例吗?为什么它比map更好?
  • 我的观点是map 将 调用回调(以实例化模型为代价)而update_all 不会调用它们。 find_each 的优点是它可以批量处理您的模型(默认一次 1000 个),而不是同时将所有模型加载到内存中(如果您有数千个模型,这可能会给您带来巨大的性能损失) . models.find_each { |m|.update_attributes(params) } 与models.each { |m|.update_attributes(params) } 或models.map { |m|.update_attributes(params) } 具有相同的效果
  • (map 和each 之间的唯一区别是它们返回的值。另外值得注意的是,如果models 不可能返回一个非常大的值,那么使用find_each 没有多大意义收藏)
猜你喜欢
  • 2017-10-09
  • 2022-08-15
  • 2023-03-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多