154 votes

Comment éviter d'exécuter des callbacks ActiveRecord ?

J'ai quelques modèles qui ont des rappels after_save. En général, cela ne pose pas de problème, mais dans certaines situations, comme lors de la création de données de développement, je souhaite enregistrer les modèles sans que les rappels soient exécutés. Existe-t-il un moyen simple de le faire ? Quelque chose de semblable à...

Person#save( :run_callbacks => false )

o

Person#save_without_callbacks

J'ai regardé dans la documentation de Rails et je n'ai rien trouvé. Cependant, d'après mon expérience, la documentation de Rails ne dit pas toujours tout.

UPDATE

J'ai trouvé un article de blog qui explique comment supprimer les callbacks d'un modèle comme celui-ci :

Foo.after_save.clear

Je n'ai pas pu trouver où cette méthode est documentée mais elle semble fonctionner.

8 votes

Si vous faites quelque chose de destructif ou de coûteux (comme l'envoi d'emails) dans un callback, je recommande de le déplacer et de le déclencher séparément du contrôleur ou ailleurs. De cette façon, vous ne pourrez pas le déclencher "accidentellement" lors du développement, etc.

2 votes

La solution que vous avez acceptée ne fonctionne pas pour moi. J'utilise rails 3. J'obtiens une erreur comme celle-ci : -- méthode indéfinie `update_without_callbacks' for #<User:0x10ae9b848>.

0 votes

Yaa cet article de blog a travaillé....

239voto

Vikrant Chaudhary Points 4306

Utilisez update_column (Rails >= v3.1) ou update_columns (Rails >= 4.0) pour sauter les callbacks et les validations. Également avec ces méthodes, updated_at es no mis à jour.

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update_column

#2 : Sauter les callbacks qui fonctionne également lors de la création d'un objet.

class Person < ActiveRecord::Base
  attr_accessor :skip_some_callbacks

  before_validation :do_something
  after_validation :do_something_else

  skip_callback :validation, :before, :do_something, if: :skip_some_callbacks
  skip_callback :validation, :after, :do_something_else, if: :skip_some_callbacks
end

person = Person.new(person_params)
person.skip_some_callbacks = true
person.save

MISE À JOUR (2020)

Apparemment Rails a toujours soutenu :if y :unless options Ainsi, le code ci-dessus peut être simplifié comme suit :

class Person < ActiveRecord::Base
  attr_accessor :skip_some_callbacks

  before_validation :do_something, unless: :skip_some_callbacks
  after_validation :do_something_else, unless: :skip_some_callbacks
end

person = Person.new(person_params)
person.skip_some_callbacks = true
person.save

2 votes

Il semble qu'elle fonctionne également avec la version 2.x, et il existe une multitude d'autres méthodes qui fonctionnent de manière similaire : guides.rubyonrails.org/

19 votes

Cela n'aborde pas :create_without_callbacks :( Comment puis-je exécuter quelque chose de similaire à cela ? (Fonctionne dans Rails2, supprimé dans Rails3).

0 votes

En supposant que @person est une variable dans un contrôleur quelque part, cette solution signifie que les personnes lisant votre classe de modèle ne seront pas en mesure de comprendre les callbacks. Ils verront after_create :something_cool et se diront "super, il se passe quelque chose de cool après la création". Pour comprendre réellement votre classe de modèle, ils devront greffer tous vos contrôleurs, à la recherche de tous les petits endroits où vous avez décidé d'injecter de la logique. Je n'aime pas ça >o< ; ;

71voto

efalcao Points 3332

Cette solution ne concerne que Rails 2.

Je viens d'enquêter sur ce sujet et je pense avoir une solution. Il existe deux méthodes privées ActiveRecord que vous pouvez utiliser :

update_without_callbacks
create_without_callbacks

Vous allez devoir utiliser send pour appeler ces méthodes. exemples :

p = Person.new(:name => 'foo')
p.send(:create_without_callbacks)

p = Person.find(1)
p.send(:update_without_callbacks)

C'est certainement quelque chose que vous ne voudrez utiliser que dans la console ou lors de tests aléatoires. J'espère que cela vous aidera !

7 votes

Cela ne fonctionne pas pour moi. J'utilise rails 3. J'obtiens une erreur comme celle-ci : -- méthode non définie `update_without_callbacks' for #<User:0x10ae9b848>.

0 votes

Votre suggestion ne fonctionne pas, mais le blog mentionné dans la partie mise à jour fonctionne

0 votes

Cela permet également d'éviter les validations.

30voto

Siwei Shen Points 5814

Mis à jour :

La solution de @Vikrant Chaudhary semble meilleure :

#Rails >= v3.1 only
@person.update_column(:some_attribute, 'value')
#Rails >= v4.0 only
@person.update_columns(attributes)

Ma réponse initiale :

voir ce lien : Comment sauter les callbacks d'ActiveRecord ?

dans Rails3,

supposons que nous ayons une définition de classe :

class User < ActiveRecord::Base
  after_save :generate_nick_name
end 

Approche1 :

User.send(:create_without_callbacks)
User.send(:update_without_callbacks)

Approche2 : Lorsque vous voulez les ignorer dans vos fichiers rspec ou autres, essayez ceci :

User.skip_callback(:save, :after, :generate_nick_name)
User.create!()

REMARQUE : une fois cette opération effectuée, si vous n'êtes pas dans l'environnement rspec, vous devez réinitialiser les rappels :

User.set_callback(:save, :after, :generate_nick_name)

fonctionne bien pour moi sur rails 3.0.5

21voto

guai Points 454

Rails 3 :

MyModel.send("_#{symbol}_callbacks") # list  
MyModel.reset_callbacks symbol # reset

11 votes

Sympa. Aussi MyModel.skip_callback(:create, :after, :my_callback) pour un contrôle précis voir la docs ActiveSupport::Callbacks::ClassMethods pour tout le lobbang

4 votes

Info utile : le "symbole" dans reset_callbacks no es :after_save mais plutôt :save . apidock.com/rails/v3.0.9/ActiveSupport/Callbacks/ClassMethods/

17voto

Sarah Mei Points 10673

Vous pourriez essayer quelque chose comme ceci dans votre modèle de personne :

after_save :something_cool, :unless => :skip_callbacks

def skip_callbacks
  ENV[RAILS_ENV] == 'development' # or something more complicated
end

EDITAR: after_save n'est pas un symbole, mais c'est au moins la 1000e fois que j'essaie d'en faire un.

1 votes

Je pense vraiment que c'est la meilleure réponse. De cette façon, la logique qui détermine quand le callback est ignoré est disponible dans le modèle, et vous n'avez pas de fragments de code délirants partout pour récupérer la logique métier, ou pour contourner l'encapsulation avec des éléments de type send . KOODOS

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X