【问题标题】:Prevent infinite loop when updating attributes within after_commit, :on => :create更新 after_commit 中的属性时防止无限循环,:on => :create
【发布时间】:2014-03-21 19:00:26
【问题描述】:

当我需要在after_commit, :on => :create 期间更新属性时,我会创建一个无限回调循环。但是,仅当我需要在此回调期间更新对象的属性时才会发生这种情况。有没有办法防止这种情况?我可以以某种方式强制模型重新加载自身,以便它知道它正在执行更新而不是创建吗?

class Doc < ActiveRecord::Base
  after_commit :generate, :on => :create

  ...

  def generate
    # some logic here that requires this model to be saved in the db

    self.update_attributes(:filename => filename) # Infinite loop begins here.
  end
end

【问题讨论】:

  • 能否分享一下服务器生成的日志。另外,如果您分享完整的generate 方法,那就太好了。
  • 我也遇到过同样的问题,我认为是bug。 after_commit 应该只触发on: :create 作为声明,但实际上它被触发了,即使它被更新了。

标签: ruby-on-rails activerecord ruby-on-rails-4 callback


【解决方案1】:

您可以使用 update_column 方法跳过模型的所有回调:

self.update_column(:filename, filename)

或者你可以使用update_all的方法,它遵循相同的行为

self.class.where('id = ?', self.id).update_all(:filename => filename)

最后但并非最不重要的是,我个人最喜欢的:

self.filename = filename
self.send(:update_without_callbacks)

这很清楚所有回调都被忽略了,非常有帮助


此外,作为另一种选择,如果您只想在保存新记录时运行 generate 方法,则可以使用 after_create 而不是 after_commit

【讨论】:

  • 仅供参考,在 Rails 3 中删除了 update_without_callbacks。但前两个建议似乎仍然有效。
【解决方案2】:

问题将是update_attributes 将启动您使用过的after_commit 回调

正如 Rafael 所说,您要么需要使用不是由 update_attributes 触发的回调,要么使用否定回调的更新方法:


update_column 不发起回调 - self.update_column(filename: filename)


after_create 仅在您创建记录(不更新)时触发 - after_create :generate

【讨论】:

    【解决方案3】:

    这是一个错误,请参阅 Github 问题https://github.com/rails/rails/issues/16286

    【讨论】:

      猜你喜欢
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 2019-11-11
      • 1970-01-01
      • 2012-05-08
      • 2020-01-09
      • 2020-05-20
      • 1970-01-01
      相关资源
      最近更新 更多