Imaginons que vous ayez une classe qui publie des articles. L'action de publication provoque l'envoie d'un e-mail au modérateur qui est averti de la nouvelle publication. Un moyen de ne pas avoir à appeler de méthode d'envoi de mail dans votre fonction de publication est d'utiliser par le pattern Observer.

Avec Rails, il est possible de déclarer des classes observatrices de vos modèles de la manière suivante.

Reprenons notre classe Article :

class Article < ActiveRecord::Base
   def publish
      @article = Article.find(params[:id])
      @article.status = "published"
      @article.save
   end
end

Vous remarquerez que dans cette classe nous n'avons pas envoyé d'email, et c'est là qu'intervient Observer. On crée une autre classe ArticleNotificationObserver qui étend la classe Observer (qui est un Singleton par ailleurs) qui va observer notre modèle.

class ArticleNotificationObserver < ActiveRecord::Observer
   observe Article
   cattr_accessor(:disabled)
    
   def after_save(article)
      unless disabled
          if status_changed? && status == 'published'
              # traitement envoi d'emails
          end
      end
   end
end

En fait Rails nous permet de capturer des callbacks, il y en a une dizaine after_save, before_save, after_update, before_update, etc... Je vous laisser aller voir les actions possibles dans la doc : .

Vous noterez également deux choses, un attribut de classe (disabled) qui sert pour que lorsque vous effectuez des migrations sur la table Article, que l'observer ne soit pas appelé en ajoutant dans votre migration :

   Article.disabled = true

et la possibilité en rails, d'appeler des méthodes "nom_colonne"_changed? et "nom_colonne".changes pour savoir si la valeur de la colonne a changé et quels en sont les changements.

Enfin, pour que cela fonctionne, il faut déclarer dans la configuration de rails (environment.rb) les observers (pensez à redémarrer le serveur):

  config.active_record.observers = :article_notification_observer

Si vous avez des corrections ou des précisions à apporter, n'hésitez pas.