web-dev-qa-db-fra.com

Comment "update_attributes" sans exécuter "before_save"?

J'ai un before_save dans mon modèle Message défini comme ceci:

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

Quand je fais:

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

foo et bar sont exécutés.

Parfois, je souhaite mettre à jour les champs du message sans exécuter foo et bar.

Comment puis-je mettre à jour, par exemple, le champ created_at (dans la base de données) sans exécuter foo et bar?

23
Misha Moroshko

Dans Rails 3.1, vous utiliserez update_column .

Autrement:

De manière générale, le moyen le plus élégant de contourner les rappels est le suivant:

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

Ensuite, vous pouvez faire:

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

Ou, juste pour un enregistrement:

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

Si vous en avez besoin spécifiquement pour un attribut Time, alors touch fera l'affaire comme indiqué par @lucapette.

34
jbescoyez

update_all ne déclenchera pas de rappel

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

17
fl00r

Utilisez la méthode touch . C'est élégant et fait exactement ce que vous voulez

6
lucapette

Vous pouvez également rendre votre action before_save conditionnelle.

Ajoutez donc une variable de champ/instance et ne la définissez que si vous voulez la sauter et vérifiez-la dans votre méthode.

Par exemple.

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

et puis quelque part écrire

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

update_column ou update_columns est la méthode la plus proche de update_attributes et évite les rappels sans avoir à contourner manuellement quoi que ce soit.

0
Archonic