I published an article on disabling ActiveModel callbacks, but I’m not completely sure this is the prettiest way to开发者_C百科 do something like this.
Mongoid::Timestamps
adds a before save callback that updates the updated_at
field. Let's say I don't want that in some cases and I disable the callback like this:
class User
# I'm using Mongoid, but this should work for anything based on
# ActiveModel.
include Mongoid::Document
include Mongoid::Timestamps
def sneaky_update(attributes)
User.skip_callback(:save, :before, :set_updated_at)
User.update_attributes(attributes)
User.set_callback(:save, :before, :set_updated_at)
end
end
Is calling skip_callback
followed by set_callback
to set the removed callback again a bad idea? How would you do this? :)
How about this?
module Mongoid
module Timestamps
attr_accessor :skip_updated_at
def set_updated_at_new
unless self.skip_updated_at
set_updated_at_org
end
end
alias set_updated_at_org set_updated_at
alias set_updated_at set_updated_at_new
end
end
class User
# I'm using Mongoid, but this should work for anything based on
# ActiveModel.
include Mongoid::Document
include Mongoid::Timestamps
def sneaky_update(attributes)
self.skip_updated_at = true
User.update_attributes(attributes)
self.skip_updated_at = false
end
end
You can skip before save callbacks and validations by using send, for example
user = User.new(:name=>'test')
user.send(:create_without_callbacks)
Your current solution seems "dangerous" in that if the update raises an exception then the callbacks don't get put back into place which could seriously break any request after it. Self modifying code is a really bad idea if it can have persistent side effects for other threads, it's a bit like using globals.
But I have the seem problem and I have been looking all around for a solution and yours has been the best I could find until now. I think Rails may need to add a more elegant way to do this to the Callback module.
精彩评论