Question

I have a before_save in my Message model defined like this:

   class Message < ActiveRecord::Base
     before_save lambda { foo(publisher); bar }
   end

When I do:

   my_message.update_attributes(:created_at => ...)

foo and bar are executed.

Sometimes, I would like to update message's fields without executing foo and bar.

How could I update, for example, the created_at field (in the database) without executing foo and bar ?

Was it helpful?

Solution

In rails 3.1 you will use update_column.

Otherwise:

In general way, the most elegant way to bypass callbacks is the following:

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

Then, you can do:

Message.skip_callbacks = true # for multiple records
my_message.update_attributes(:created_at => ...)
Message.skip_callbacks = false # reset

Or, just for one record:

my_message.update_attributes(:created_at => ..., :skip_callbacks => true)

If you need it specifically for a Time attribute, then touch will do the trick as mentioned by @lucapette .

OTHER TIPS

update_all won't trigger callbacks

my_message.update_all(:created_at => ...)
# OR
Message.update_all({:created_at => ...}, {:id => my_message.id})

http://apidock.com/rails/ActiveRecord/Base/update_all/class

Use the touch method. It's elegant and does exactly what you want

You could also make your before_save action conditional.

So add some field/instance variable, and set it only if you want to skip it, and check that in your method.

E.g.

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

and then somewhere write

my_message.skip_before_save = true
my_message.update_attributes(:created_at => ...)

update_column or update_columns is the closest method to update_attributes and it avoids callbacks without having to manually circumvent anything.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top