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
?
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.
update_all
ne déclenchera pas de rappel
my_message.update_all(:created_at => ...)
# OR
Message.update_all({:created_at => ...}, {:id => my_message.id})
Utilisez la méthode touch . C'est élégant et fait exactement ce que vous voulez
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 => ...)
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.