【问题标题】:How to skip ActiveRecord callbacks? [duplicate]如何跳过 ActiveRecord 回调? [复制]
【发布时间】:2010-11-23 11:41:29
【问题描述】:

可能重复:
How can I avoid running ActiveRecord callbacks?

我有这样的模型

class Vote < ActiveRecord::Base  
    after_save :add_points_to_user

    .....
end

是否有可能以某种方式强制模型在保存时跳过调用add_points_to_user?可能是 ActiveRecord#deleteActiveRecord#destroy 之类的东西?

【问题讨论】:

  • 在我看来,声称已经有答案的问题,只有破碎的答案。所以我不认为这有资格作为重复。我认为我在下面提供的答案是官方认可的避免回调方法。

标签: ruby-on-rails rails-activerecord


【解决方案1】:

对于 Rails 2,但不是 Rails 3,您可以使用这些:

object.send(:create_without_callbacks)
object.send(:update_without_callbacks)

【讨论】:

  • 不幸的是,这不再适用于 Rails 3 :(
  • 查看我的回答以获取涵盖 Rails 2 和 Rails 3 的建议。
  • Model 具有误导性,这些是 AR 实例的方法,而不是类方法,所以 record.send(:create_without_callbacks)
  • @tokland 刚刚看到这个答案,并得到了您的评论的帮助,更新了答案。
【解决方案2】:

对于 Rails 3,ActiveSupport::Callbacks 为您提供必要的控制。我刚刚在数据集成场景中面临同样的挑战,在这种场景中,通常理想的回调需要被置之不理。您可以整体重置回调,或使用 skip_callback 明智地禁用,如下所示:

Vote.skip_callback(:save, :after, :add_points_to_user)

..之后您可以在 :add_points_to_user 禁止的情况下对投票实例进行操作

【讨论】:

  • 如果您不想永久摆脱回调,但只说一次创建/保存,那么您必须在完成跳过回调后重新启用它:User.set_callback :save, :after, :add_points_to_user 也这样做请注意,如果您在两次调用之间所做的任何事情都可能引发异常,您可能应该将其包裹在 begin(-rescue)-ensure-block 周围。
  • 特定实例是否有类似的功能?
  • 我可能建议的是,使用:if 选项(如if: lambda { @skip_callbacks == true })在类上以声明方式设置skip_callback,并编写方法来包装需要执行此操作的案例:@987654329 @ 可以使用上下文管理器方法来设置/取消设置 ivar 并生成块,但是如果您经常需要这个,可能会有问题 ;-) edit 呃,我讨厌 SO 注释换行限制。
  • 注意skip_callbackset_callback 如何影响回调顺序。如果我正确阅读了source code,他们实际上会删除并重新添加回调。默认情况下,它被添加到链的end。设置时,可以使用:prepend =&gt; :true强制到链首。如果跳过/设置实际上在不影响序列的情况下进行了停用/重新激活,那就太好了。我的例子是this answer
  • 这不是线程安全的。因此,如果您在多线程服务器上运行此程序,请务必小心。
【解决方案3】:

以下适用于轨道 2、轨道 3 和轨道 4:

http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#skipping-callbacks

它提供了一个跳过回调的方法列表,解释了为什么在没有仔细考虑的情况下使用它们是危险的。根据知识共享署名-相同方式共享 3.0 许可的规定在此转载。

12 跳过回调

就像验证一样,也可以跳过回调。这些 但是,应谨慎使用方法,因为重要 业务规则和应用程序逻辑可以保存在回调中。 在不了解潜在影响的情况下绕过它们可能 导致数据无效。

  • 递减
  • decrement_counter
  • 删除
  • 删除全部
  • find_by_sql
  • 增量
  • increment_counter
  • 切换
  • 触摸
  • update_column
  • update_all
  • update_counters

【讨论】:

  • 据我所知,在 Rails 4.2 中,切换只更改对象,但不保存到数据库,您需要在切换后调用保存方法。如果使用toggle!,它现在保存,但它会触发回调,所以,它应该从这个列表中删除。
  • @zw963 但是切换!不在列表中,因此不需要删除。您是说非爆炸切换也会触发回调,因此需要删除?关于 ActiveRecord 回调的 Rails 指南仍然列出了在 4.2.1 中跳过回调的方法之间的切换。
  • 我的理解是有些方法可以将数据保存到数据库,并且不会触发回调,它应该在列表中。但是,切换不是保存数据。
  • 啊,现在我明白了。不,这不是修改数据库的方法列表。它是一个方法列表,可以修改模型的状态(持久或不持久),而不会触发与修改后的属性关联的回调。我很欣赏最初的问题专门询问了有关在保存时跳过验证的问题,但我不希望编辑引用的文本。
【解决方案4】:

这将跳过您的验证:

vote.save(:validate => false)

更多信息here

要跳过回调和验证,您可以使用 update_column v(3.1) 或 update_all

vote = Vote.first
vote.update_column(:subject, 'CallBacks')

显然这只适用于 ActiveRecord 3.1

或者:

Vote.where('id = ?', YourID).update_all(:subject => 'CallBacks')

最后你还有 i finally 选项,这将跳过一切:

execute "UPDATE votes SET subject = 'CallBacks' WHERE id = YourID"

好吧,最后一个不太漂亮。

【讨论】:

  • 这不会跳过回调,只是验证
  • update_all 会跳过来自 apidock.com/rails/ActiveRecord/Relation/update_all 的回调:“它不会实例化相关模型,也不会触发 Active Record 回调或验证。”
  • update_column 也可以,只是上面的语法不正确。它需要 2 个参数:vote.update_column(:subject, 'CallBacks')
猜你喜欢
  • 1970-01-01
  • 2014-05-05
  • 2019-10-11
  • 2016-10-16
  • 2011-03-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多