Ruby-on-rails 如何避免运行 ActiveRecord 回调?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/632742/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I avoid running ActiveRecord callbacks?
提问by Ethan
I have some models that have after_save callbacks. Usually that's fine, but in some situations, like when creating development data, I want to save the models without having the callbacks run. Is there a simple way to do that? Something akin to...
我有一些具有 after_save 回调的模型。通常这很好,但在某些情况下,例如在创建开发数据时,我想在不运行回调的情况下保存模型。有没有一种简单的方法可以做到这一点?类似于...
Person#save( :run_callbacks => false )
or
或者
Person#save_without_callbacks
I looked in the Rails docs and didn't find anything. However in my experience the Rails docs don't always tell the whole story.
我查看了 Rails 文档并没有找到任何东西。然而,根据我的经验,Rails 文档并不总是能讲述整个故事。
UPDATE
更新
I found a blog postthat explains how you can remove callbacks from a model like this:
我找到了一篇博客文章,解释了如何从这样的模型中删除回调:
Foo.after_save.clear
I couldn't find where that method is documented but it seems to work.
我找不到记录该方法的位置,但它似乎有效。
采纳答案by efalcao
This solution is Rails 2 only.
此解决方案仅适用于 Rails 2。
I just investigated this and I think I have a solution. There are two ActiveRecord private methods that you can use:
我刚刚调查了这个,我想我有一个解决方案。您可以使用两种 ActiveRecord 私有方法:
update_without_callbacks
create_without_callbacks
You're going to have to use send to call these methods. examples:
您将不得不使用 send 来调用这些方法。例子:
p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)
p = Person.find(1)
p.send(:update_without_callbacks)
This is definitely something that you'll only really want to use in the console or while doing some random tests. Hope this helps!
这绝对是您真正想要在控制台中或在进行一些随机测试时使用的东西。希望这可以帮助!
回答by Vikrant Chaudhary
Use update_column(Rails >= v3.1) or update_columns(Rails >= 4.0) to skip callbacks and validations. Also with these methods, updated_atis notupdated.
使用update_column(Rails >= v3.1) 或update_columns(Rails >= 4.0) 跳过回调和验证。同时这些方法,updated_at是不更新。
#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column
#2: Skipping callbacks that also works while creating an object
#2:跳过在创建对象时也有效的回调
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
回答by u445908
Updated:
更新:
@Vikrant Chaudhary's solution seems better:
@Vikrant Chaudhary 的解决方案似乎更好:
#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
My original answer :
我原来的回答:
see this link: How to skip ActiveRecord callbacks?
请参阅此链接: 如何跳过 ActiveRecord 回调?
in Rails3,
在 Rails3 中,
assume we have a class definition:
假设我们有一个类定义:
class User < ActiveRecord::Base
after_save :generate_nick_name
end
Approach1:
方法一:
User.send(:create_without_callbacks)
User.send(:update_without_callbacks)
Approach2: When you want to skip them in your rspec files or whatever, try this:
方法 2:当您想在 rspec 文件或其他文件中跳过它们时,请尝试以下操作:
User.skip_callback(:save, :after, :generate_nick_name)
User.create!()
NOTE: once this is done, if you are not in rspec environment, you should reset the callbacks:
注意:一旦完成,如果您不在 rspec 环境中,您应该重置回调:
User.set_callback(:save, :after, :generate_nick_name)
works fine for me on rails 3.0.5
在 Rails 3.0.5 上对我来说很好用
回答by guai
rails 3:
导轨 3:
MyModel.send("_#{symbol}_callbacks") # list
MyModel.reset_callbacks symbol # reset
回答by Brad Werth
If the goal is to simply insert a record without callbacks or validations, and you would like to do it without resorting to additional gems, adding conditional checks, using RAW SQL, or futzing with your exiting code in any way, consider using a "shadow object" pointing to your existing db table. Like so:
如果目标是在没有回调或验证的情况下简单地插入记录,并且您希望在不求助于其他 gem、添加条件检查、使用 RAW SQL 或以任何方式处理现有代码的情况下执行此操作,请考虑使用“影子”对象”指向您现有的数据库表。像这样:
class ImportedPerson < ActiveRecord::Base
self.table_name = 'people'
end
This works with every version of Rails, is threadsafe, and completely eliminates all validations and callbacks with no modifications to your existing code. You can just toss that class declaration in right before your actual import, and you should be good to go. Just remember to use your new class to insert the object, like:
这适用于每个版本的 Rails,是线程安全的,并且完全消除了所有验证和回调,而无需修改现有代码。您可以在实际导入之前直接抛出该类声明,您应该很高兴。请记住使用您的新类插入对象,例如:
ImportedPerson.new( person_attributes )
回答by Sarah Mei
You could try something like this in your Person model:
你可以在你的 Person 模型中尝试这样的事情:
after_save :something_cool, :unless => :skip_callbacks
def skip_callbacks
ENV[RAILS_ENV] == 'development' # or something more complicated
end
EDIT:after_save is not a symbol, but that's at least the 1,000th time I've tried to make it one.
编辑:after_save 不是一个符号,但这至少是我第 1000 次尝试将其变成一个符号。
回答by Luís Ramalho
You can use update_columns:
您可以使用update_columns:
User.first.update_columns({:name => "sebastian", :age => 25})
Updates the given attributes of an object, without calling save, hence skipping validations and callbacks.
更新对象的给定属性,而不调用 save,因此跳过验证和回调。
回答by rfunduk
The only way to prevent all after_save callbacks is to have the first one return false.
阻止所有 after_save 回调的唯一方法是让第一个回调返回 false。
Perhaps you could try something like (untested):
也许你可以尝试类似(未经测试):
class MyModel < ActiveRecord::Base
attr_accessor :skip_after_save
def after_save
return false if @skip_after_save
... blah blah ...
end
end
...
m = MyModel.new # ... etc etc
m.skip_after_save = true
m.save
回答by chrisrbailey
Looks like one way to handle this in Rails 2.3 (since update_without_callbacks is gone, etc.), would be to use update_all, which is one of the methods that skips callbacks as per section 12 of the Rails Guide to validations and callbacks.
看起来像在 Rails 2.3 中处理这个问题的一种方法(因为 update_without_callbacks 消失了,等等),将使用 update_all,这是根据 Rails Guide to validations and callbacks 的第 12 节跳过回调的方法之一。
Also, note that if you are doing something in your after_ callback, that does a calculation based on many association (i.e. a has_many assoc, where you also do accepts_nested_attributes_for), you will need to reload the association, in case as part of the save, one of its members was deleted.
另外,请注意,如果您在 after_ 回调中执行某些操作,它会根据许多关联进行计算(即 has_many 关联,您也可以在其中执行 accepts_nested_attributes_for),您将需要重新加载关联,以防作为保存的一部分,其中一名成员被删除。
回答by fringd
https://gist.github.com/576546
https://gist.github.com/576546
just dump this monkey-patch into config/initializers/skip_callbacks.rb
只需将这个猴子补丁转储到 config/initializers/skip_callbacks.rb
then
然后
Project.skip_callbacks { @project.save }
Project.skip_callbacks { @project.save }
or the like.
或类似。
all credit to the author
所有功劳归功于作者

