如何避免运行ActiveRecord回调?

Eth*_*han 137 ruby ruby-on-rails rails-activerecord

我有一些具有after_save回调的模型.通常这很好,但在某些情况下,比如在创建开发数据时,我想保存模型而不运行回调.有一个简单的方法吗?类似于......的东西

Person#save( :run_callbacks => false )
Run Code Online (Sandbox Code Playgroud)

要么

Person#save_without_callbacks
Run Code Online (Sandbox Code Playgroud)

我查看了Rails文档但没有找到任何内容.但是根据我的经验,Rails文档并不总是讲述整个故事.

UPDATE

我发现了一篇博文,解释了如何从这样的模型中删除回调:

Foo.after_save.clear
Run Code Online (Sandbox Code Playgroud)

我找不到该方法的记录,但似乎有效.

Vik*_*ary 220

使用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)
Run Code Online (Sandbox Code Playgroud)

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

#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
Run Code Online (Sandbox Code Playgroud)

  • 这不解决`:create_without_callbacks` :(我怎么能运行类似的东西?(在Rails2中工作,在Rails3中删除). (15认同)
  • 看起来它也适用于2.x,并且还有许多其他类似的方法:http://guides.rubyonrails.org/active_record_validations_callbacks.html#skipping-callbacks (2认同)

efa*_*cao 72

此解决方案仅适用于Rails 2.

我只是调查了这个,我想我有一个解决方案.您可以使用两种ActiveRecord私有方法:

update_without_callbacks
create_without_callbacks
Run Code Online (Sandbox Code Playgroud)

您将不得不使用send来调用这些方法.例子:

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)
Run Code Online (Sandbox Code Playgroud)

这绝对是你真正想要在控制台中或在进行一些随机测试时使用的东西.希望这可以帮助!

  • 它不适合我.我正在使用rails 3.我收到这样的错误: - 针对#<User:0x10ae9b848>的未定义方法`update_without_callbacks' (7认同)

Siw*_*申思维 28


更新:

@Vikrant Chaudhary的解决方案似乎更好:

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)
Run Code Online (Sandbox Code Playgroud)

我的原始答案:

看到这个链接: 如何跳过ActiveRecord回调?

在Rails3中,

假设我们有一个类定义:

class User < ActiveRecord::Base
  after_save :generate_nick_name
end 
Run Code Online (Sandbox Code Playgroud)

Approach1:

User.send(:create_without_callbacks)
User.send(:update_without_callbacks)
Run Code Online (Sandbox Code Playgroud)

方法2:当你想在你的rspec文件或其他任何内容中跳过它们时,试试这个:

User.skip_callback(:save, :after, :generate_nick_name)
User.create!()
Run Code Online (Sandbox Code Playgroud)

注意:完成此操作后,如果您不在rspec环境中,则应重置回调:

User.set_callback(:save, :after, :generate_nick_name)
Run Code Online (Sandbox Code Playgroud)

在rails 3.0.5上工作正常


gua*_*uai 20

铁轨3:

MyModel.send("_#{symbol}_callbacks") # list  
MyModel.reset_callbacks symbol # reset
Run Code Online (Sandbox Code Playgroud)

  • 尼斯.还有MyModel.skip_callback(:create,:after,:my_callback)用于精确控制..请参阅所有lobang的ActiveSupport :: Callbacks :: ClassMethods文档 (11认同)
  • 有用的信息:`reset_callbacks`中的'symbol'不是`:after_save`,而是`:save`.http://apidock.com/rails/v3.0.9/ActiveSupport/Callbacks/ClassMethods/reset_callbacks (4认同)

Sar*_*Mei 17

您可以在Person模型中尝试这样的事情:

after_save :something_cool, :unless => :skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end
Run Code Online (Sandbox Code Playgroud)

编辑: after_save不是一个符号,但这至少是我试图使其成为第一次的第1000次.


Bra*_*rth 17

如果目标是简单地插入没有回调或验证的记录,并且您希望在不借助其他宝石,添加条件检查,使用RAW SQL或以任何方式使用现有代码的情况下执行此操作,请考虑使用"阴影"对象"指向您现有的数据库表.像这样:

class ImportedPerson < ActiveRecord::Base
  self.table_name = 'people'
end
Run Code Online (Sandbox Code Playgroud)

这适用于每个版本的Rails,线程安全,完全消除所有验证和回调,而无需修改现有代码.你可以在实际导入之前就把这个类声明扔掉,你应该好好去.只需记住使用新类插入对象,例如:

ImportedPerson.new( person_attributes )
Run Code Online (Sandbox Code Playgroud)

  • 最佳解决方案EVER.优雅而简单! (4认同)

Luí*_*lho 9

你可以使用update_columns:

User.first.update_columns({:name => "sebastian", :age => 25})
Run Code Online (Sandbox Code Playgroud)

更新对象的给定属性,而不调用save,因此跳过验证和回调.


rfu*_*duk 7

防止所有after_save回调的唯一方法是让第一个返回false.

也许你可以试试(未经测试):

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
Run Code Online (Sandbox Code Playgroud)


chr*_*ley 5

看起来在Rails 2.3中处理这种情况的一种方法(因为update_without_callbacks已经消失等),将使用update_all,这是根据Rails指南第12节对验证和回调跳过回调的方法之一.

另外,请注意,如果您在after_回调中执行某些操作,即基于多个关联(即has_many assoc,您也执行accepts_nested_attributes_for)进行计算,则需要重新加载关联,以防作为保存的一部分,其中一名成员被删除.


Ale*_*eks 5

up-voted在某些情况下,大多数答案可能看起来令人困惑。

if如果您想跳过回调,您可以只使用一个简单的检查,如下所示:

after_save :set_title, if: -> { !new_record? && self.name_changed? }
Run Code Online (Sandbox Code Playgroud)