How to "update_attributes" without executing "before_save"?

29,903

Solution 1

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 .

Solution 2

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

Solution 3

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

Solution 4

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 => ...)

Solution 5

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

Share:
29,903
Misha Moroshko
Author by

Misha Moroshko

I build products that make humans happier. Previously Front End engineer at Facebook. Now, reimagining live experiences at https://muso.live

Updated on October 14, 2020

Comments

  • Misha Moroshko
    Misha Moroshko over 3 years

    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 ?