Как "update_attributes" без выполнения "before_save"?

У меня есть before_save в моей модели Message, подобной этой:

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

Когда я это сделаю:

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

foo и bar.

Иногда я хотел бы обновлять поля сообщений без выполнения foo и bar.

Как я могу обновить, например, поле created_at (в базе данных) без выполнения foo и bar?

Ответ 1

В rails 3.1 вы будете использовать update_column.

В противном случае:

В общем случае наиболее элегантным способом обхода обратных вызовов является следующее:

class Message < ActiveRecord::Base
  cattr_accessor :skip_callbacks
  before_save lambda { foo(publisher); bar }, :unless => :skip_callbacks # let 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 выполнит трюк, как указано в @lucapette.

Ответ 3

Используйте метод touch. Он элегантный и делает именно то, что вы хотите

Ответ 4

Вы также можете сделать действие before_save условным.

Итак, добавьте переменную field/instance и установите ее только в том случае, если вы хотите пропустить ее, и проверьте это в своем методе.

например.

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

Ответ 5

update_column или update_columns является самым близким методом к update_attributes, и он избегает обратных вызовов без необходимости вручную обойти что-либо.