如何在不执行“before_save”的情况下“update_attributes”?
我的Message
模型中的before_save
定义如下:
class Message < ActiveRecord::Base before_save lambda { foo(publisher); bar } end
当我做:
my_message.update_attributes(:created_at => ...)
foo
和bar
被执行。
有时,我想更新消息的字段而不执行foo
和bar
。
如何在不执行foo
和bar
情况下更新created_at
字段(在数据库中)?
在rails 3.1中,您将使用update_column 。
除此以外:
一般来说,绕过回调最优雅的方法如下:
class Message < ActiveRecord::Base cattr_accessor :skip_callbacks before_save lambda { foo(publisher); bar }, :unless => :skip_callbacks # let's say you do not want this callback to be triggered when you perform batch operations end
然后,你可以这样做:
Message.skip_callbacks = true # for multiple records my_message.update_attributes(:created_at => ...) Message.skip_callbacks = false # reset
或者,只为一个记录:
my_message.update_attributes(:created_at => ..., :skip_callbacks => true)
如果你需要专门为Time
属性,那么touch
将完成@luttette提到的技巧。
update_all
不会触发回调
my_message.update_all(:created_at => ...) # OR Message.update_all({:created_at => ...}, {:id => my_message.id})
使用触摸方法。 它很优雅,完全符合您的要求
您还可以使before_save
操作有条件。
因此,添加一些字段/实例变量,并仅在您想要跳过它时设置它,并在您的方法中检查它。
例如
before_save :do_foo_and_bar_if_allowed attr_accessor :skip_before_save def do_foo_and_bar_if_allowed unless @skip_before_save.present? foo(publisher) bar end end
然后在某处写
my_message.skip_before_save = true my_message.update_attributes(:created_at => ...)
update_column
或update_columns
是最接近update_attributes
方法,它避免了回调而不必手动规避任何事情。