如何避免运行ActiveRecord回调函数?
如何避免运行ActiveRecord回调函数?
我有一些模型,其中有一些在保存后执行的回调函数。通常情况下这是可以的,但在某些情况下,比如创建开发数据时,我希望保存模型时不要运行这些回调函数。有没有一种简单的方法可以做到这一点?类似于...
Person#save( :run_callbacks => false )
或者
Person#save_without_callbacks
我查了一下Rails文档,没有找到相关内容。但是根据我的经验,Rails文档并不总是完整的。
更新
我找到了一篇博客文章,解释了如何像这样从模型中移除回调函数:
Foo.after_save.clear
我找不到这个方法在哪里有文档记录,但它似乎有效。
如何避免运行ActiveRecord回调?
在Rails中,有时候我们希望在特定情况下避免运行ActiveRecord回调。这可能是因为回调函数执行的操作过于耗时,或者我们在某个特定的环境下不需要执行这些回调。下面我们将介绍一些解决方法。
1. 使用send
方法跳过回调函数
在Rails3中,我们可以通过send
方法来跳过ActiveRecord回调函数。例如,假设我们有一个User类定义,其中包含一个在保存后生成昵称的回调函数:after_save :generate_nick_name
。
我们可以使用send
方法来跳过回调函数的执行:
User.send(:create_without_callbacks) User.send(:update_without_callbacks)
2. 使用skip_callback
方法跳过回调函数
在RSpec文件或其他需要跳过回调函数的地方,我们可以使用skip_callback
方法。例如,假设我们想在某个测试中跳过保存后生成昵称的回调函数:
User.skip_callback(:save, :after, :generate_nick_name) User.create!()
需要注意的是,一旦我们使用skip_callback
方法跳过了回调函数,如果不在RSpec环境中,我们需要重置回调函数:User.set_callback(:save, :after, :generate_nick_name)
。
以上方法在Rails 3.0.5中测试通过,并且可以正常跳过ActiveRecord回调函数的执行。如果你在其他版本的Rails中使用这些方法,可能会有所不同。
更多关于如何跳过ActiveRecord回调函数的信息,可以参考这个链接:How to skip ActiveRecord callbacks?。
如何避免运行ActiveRecord回调函数?
在Rails 2中,有两个可以使用的ActiveRecord私有方法,它们是:
update_without_callbacks create_without_callbacks
你需要使用send
来调用这些方法,例如:
p = Person.new(:name => 'foo') p.send(:create_without_callbacks) p = Person.find(1) p.send(:update_without_callbacks)
这只是在控制台或进行一些随机测试时才会用到的东西。希望这能有所帮助!
对于我来说这个方法行不通。我正在使用Rails 3,我遇到了这个错误:undefined method 'update_without_callbacks' for #
你的建议不起作用,但是在更新部分提到的博客文章是有效的。
这也会跳过验证。
我有另一种适用于任何版本的Rails的解决方案,它对我们很有效。请在我的博客文章中查看:railsguides.net/2014/03/25/skip-callbacks-in-tests
如何避免运行ActiveRecord回调函数?
在Rails中,我们可以使用update_column
(Rails >= v3.1)或update_columns
(Rails >= 4.0)来跳过回调和验证。同时,这些方法不会更新updated_at
字段。
在创建对象时,我们也可以跳过回调函数。例如,我们可以在模型中设置一个属性skip_some_callbacks
,然后使用skip_callback
方法来跳过指定回调函数:
class Person < ActiveRecord::Base attr_accessor :skip_some_callbacks before_validation :do_something after_validation :do_something_else skip_callback :validation, :before, :do_something, if: :skip_some_callbacks skip_callback :validation, :after, :do_something_else, if: :skip_some_callbacks end person = Person.new(person_params) person.skip_some_callbacks = true person.save
然而,Rails在更新版本中已经支持使用:if
和:unless
选项来跳过回调函数。因此,上述代码可以简化为:
class Person < ActiveRecord::Base attr_accessor :skip_some_callbacks before_validation :do_something, unless: :skip_some_callbacks after_validation :do_something_else, unless: :skip_some_callbacks end person = Person.new(person_params) person.skip_some_callbacks = true person.save
这种方法在Rails 2.x版本中也可以使用,并且还有其他一些类似的方法可以实现类似的功能。
不过,这种方法无法解决:create_without_callbacks
的问题。在Rails2中,我们可以使用:create_without_callbacks
来跳过所有回调函数,但在Rails3中被移除了。
需要注意的是,使用上述方法可能会导致其他开发者在阅读模型类时难以理解回调函数的执行逻辑。他们看到after_create :something_cool
,会以为"嗯,创建后会执行一些酷炫的操作!",但实际上,他们需要在所有控制器中搜索并查找你注入逻辑的地方。这种方式可能不太友好。
如果想正确运行after_create
回调函数,可以将skip_callback
替换为after_create
并使用unless
选项来判断是否跳过回调函数的执行。
总结起来,我们可以通过使用update_column
或update_columns
方法来跳过回调函数和验证,也可以使用skip_callback
方法来选择性地跳过指定的回调函数。不过,需要注意代码的可读性和维护性。