Как обновить_атрибуты без выполнения 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?


person Misha Moroshko    schedule 30.08.2011    source источник


Ответы (5)


В 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 сделает то же самое, о чем упоминал @lucapette.

person jbescoyez    schedule 30.08.2011
comment
Похоже на хорошее общее решение! Один вопрос: что именно Message.batch = true делать? - person Misha Moroshko; 30.08.2011
comment
Это просто флаг. Вы можете заменить его чем хотите. - person jbescoyez; 30.08.2011
comment
Это не будет работать с сериализованными столбцами (то есть update_column), поскольку по какой-то причине он также пропускает сериализацию / десериализацию. - person bouchard; 29.08.2012
comment
Стоит отметить, что использование update_column также означает, что проверки не выполняются. - person In-flux; 11.09.2012
comment
Поскольку вы устанавливаете атрибут в классе, это не кажется очень потокобезопасным. Мысли? - person elsurudo; 03.07.2016

update_all не будет вызывать обратные вызовы

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

person fl00r    schedule 30.08.2011
comment
my_message.update_all(:created_at => ...) выдает синтаксическую ошибку, но второй вариант работает нормально! - person Misha Moroshko; 30.08.2011
comment
my_message.update_all вызовет undefined method update_all. Message.update_all сделает свое дело - person Arivarasan L; 26.02.2014
comment
Возможно, вы сможете использовать increment_counter [если это счетчик, который вы хотите увеличить], который, как я полагаю, также пропускает обратные вызовы. - person rogerdpack; 19.08.2014
comment
для работы с экземпляром вы можете использовать update_column или update_columns, чтобы избежать обратных вызовов - person goodniceweb; 24.11.2015

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

person lucapette    schedule 30.08.2011
comment
Похоже, почти то, что мне нужно. Новое значение created_at в моем случае не текущего времени. - person Misha Moroshko; 30.08.2011
comment
@ Миша, ты, очевидно, прав. Таким образом, вы можете использовать api.rubyonrails.org/classes/ActiveRecord/: D - person lucapette; 30.08.2011
comment
@lucapette: Как? В документации сказано, что update_attribute вызывает обратные вызовы. - person Misha Moroshko; 30.08.2011
comment
@ Миша, ты не можешь. Думая о вашей проблеме, я путал обратные вызовы с проверкой ... Поэтому я думаю, вам следует использовать update_all. Кстати, см. edgeguides.rubyonrails.org/, может быть, есть что-то такое. м с видом - person lucapette; 30.08.2011

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

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

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

а потом куда-нибудь напиши

my_message.skip_before_save = true
my_message.update_attributes(:created_at => ...)
person nathanvda    schedule 30.08.2011

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

person Archonic    schedule 13.10.2017
comment
api.rubyonrails.org/classes/ActiveRecord/ - person ronnie bermejo; 11.04.2021