Exécuter un rappel uniquement si un attribut a changé dans Rails

94

J'ai l'association suivante dans mon application:

# Page 
belongs_to :status

Je veux lancer un rappel à chaque fois que le status_idde a pagea changé.

Donc, si page.status_idpasse de 4 à 5, je veux être en mesure de saisir cela.

Comment faire cela?

Hommer Smith
la source

Réponses:

198

Rails 5.1+

class Page < ActiveRecord::Base
  before_save :do_something, if: :will_save_change_to_status_id?

  private

  def do_something
    # ...
  end
end

Le commit qui a changé ActiveRecord :: Dirty est ici: https://github.com/rails/rails/commit/16ae3db5a5c6a08383b974ae6c96faac5b4a3c81

Voici un article de blog sur ces changements: https://www.ombulabs.com/blog/rails/upgrades/active-record-5-1-api-changes.html

Voici le résumé que j'ai fait pour moi-même sur les modifications apportées à ActiveRecord :: Dirty in Rails 5.1+:

ActiveRecord :: Sale

https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html

Avant de sauvegarder (CHANGEMENT OPTIONNEL)

Après avoir modifié un objet et avant de l'enregistrer dans la base de données, ou dans le before_savefiltre:

  • changes devrait maintenant être changes_to_save
  • changed? devrait maintenant être has_changes_to_save?
  • changed devrait maintenant être changed_attribute_names_to_save
  • <attribute>_change devrait maintenant être <attribute>_change_to_be_saved
  • <attribute>_changed? devrait maintenant être will_save_change_to_<attribute>?
  • <attribute>_was devrait maintenant être <attribute>_in_database

Après l'enregistrement (BREAKING CHANGE)

Après la modification d' un objet et après la sauvegarde de la base de données, ou dans le after_savefiltre:

  • saved_changes(remplace previous_changes)
  • saved_changes?
  • saved_change_to_<attribute>
  • saved_change_to_<attribute>?
  • <attribute>_before_last_save

Rails <= 5,0

class Page < ActiveRecord::Base
  before_save :do_something, if: :status_id_changed?

  private

  def do_something
    # ...
  end
end

Cela utilise le fait que le before_saverappel peut s'exécuter conditionnellement en fonction de la valeur de retour d'un appel de méthode. La status_id_changed?méthode vient d' ActiveModel :: Dirty , qui nous permet de vérifier si un attribut spécifique a changé en l'ajoutant simplement _changed?au nom de l'attribut.

Le moment où la do_somethingméthode doit être appelée dépend de vos besoins. Il peut s'agir de before_saveou after_saveou de l'un des ActiveRecord :: Callbacks définis .

pdobb
la source
4
Cette solution est obsolète dans les versions plus récentes.
Mateus Luiz
6
Mis à jour avec les informations Rails 5.1+.
pdobb
16

Le attribute_changed?est obsolète dans Rails 5.1, il suffit maintenant de l'utiliser will_save_change_to_attribute?.

Pour plus d'informations, consultez ce problème .

Mateus Luiz
la source