« Ruby on Rails : Filtres, Flashes, Partielles, Squelettes ... »
Le 22 février 2009
Ruby on Rails
Aujourd’hui, nous allons reprendre le cours de l’article précédent, qui posait les bases du fonctionnement de Ruby on Rails et approfondir un peu l’aspect technique des choses en ce qui concerne les Vues & Contrôleurs.
Gestion de flux avec les Filtres
Ruby on Rails intègre un mécanisme puissant qui lui permet d’exécuter certaines actions de votre contrôleur avant ou après traitement de la requête, ce grâce aux méthodes de classe before_filter et after_filter qui sont disponibles pour tout Contrôleur.
Une des nombreuses utilisations de ce genre de mécanisme est, par exemple, un système de statistique qui vient se greffer très simplement à votre application. Pour cela, nous plaçons simplement une méthode privée dans notre Contrôleur Application (dans le fichier app/controllers/application.rb). Comme nous l’avons vu dans le précédent article, les contrôleurs de votre application héritent naturellement de ce même contrôleur : c’est donc naturellement l’endroit rêvé où placer du code qui va être accessible par tous les contrôleurs (authentification, statistiques, etc.).
Les dernières lignes de cet extrait de code illustrent à merveille la beauté de Ruby : nous ouvrons d’abord un fichier (RAILS_ROOT est une simple constante qui contient le chemin complet de l’application) puis travaillons sur son instance, placée dans la variable locale f. C’est sur cet objet que nous allons écrire pour stocker les informations que nous avons relevées, grâce à la méthode write. Enfin, lorsque le bloc de code s’achève, la méthode close de l’objet File est automatiquement appelée et le fichier est ainsi fermé correctement.
Remarquez également la syntaxe "#{blah}" : dans les chaines avec des guillemets doubles, elle nous permet d’intégrer du code Ruby à une chaine de caractère sans risquer une exception (si la valeur est nil, par exemple), contrairement à une simple concaténation.
Réutilisation de code
Nous avons vu précédement le principe MVC qui régit la conception des applications Rails, aujourd’hui en voiçi un autre : DRY, ou Don’t Repeat Yourself. L’idée est de limiter au maximum la duplication inutile de code, qui ne peut amener que des ennuis à mesure que notre application va grandir.
Pour cela, Rails met à notre disposition un arsenal d’outils que nous allons voir et qui devraient vous servir fréquemment dès que vous commencerez à développer.
Vues partielles
Souvent, nous savons par avance qu’un élément va être répété à divers endroits de l’application de façon visuellement similaire parce qu’il constitue un "tout" cohérent : par exemple un commentaire pour un blog, un message de forum, une carte d’identité d’un utilisateur avec sa photo et son login, un élement de liste etc. Les vues partielles nous permettent de capitaliser des bouts de codes qu’il sera ensuite aisé d’intégrer à notre application.
Ici, j’ai pris l’exemple d’une liste d’utilisateurs que nous allons afficher sur la page d’accueil de notre site. Voiçi tout d’abord le contrôleur qui crée un simple tableau contenant des Hashes, une sorte de tableau associatif. Ces Hashes contiennent quelques informations concernant les utilisateurs.
Voici maintenant la page d’accueil du site en question.
Comme on le voit dans cet exemple il serait intéressant de placer à part un élément "utilisateur", car on sait qu’il sera utilisé dans une ou plusieurs autres listes, à d’autres endroits dans le site sous la même forme (liste des derniers inscrits, membres les plus en vue, etc.).
Créons pour cela un nouveau fichier appelé _utilisateur.html.erb dans le répertoire app/views/utilisateurs/ que nous allons également créer. Notez bien le "_" devant le nom du fichier, c’est ce qui distingue une vue partielle d’une vue standard. Voiçi le contenu de ce fichier :
Comme vous le voyez, j’ai naturellement utilisé la variable utilisateur, car c’est celle que Rails fournit par défaut dans la Vue Partielles dans ce cas là (il s’agit du nom de la vue partielle). Notez qu’il ne s’agit plus là d’une variable d’instance, et qu’il vaut mieux éviter ce genre de variables à cet endroit là !
Remplaçons maintenant dans la vue la boucle for...each par l’extrait suivant :
Il nous faut maintenant rendre cela un peu plus explicite : nous indiquons à Rails qu’il doit rendre une Vue Partielle en lui indiquant le chemin qui y conduit (sans le _ cette fois-ci) et nous lui indiquons également d’itérer sur chaque élément de la collection @utilisateurs. Comme nous le voyons plus haut chaque élément traité sera disponible en tant que utilisateur, car c’est le nom de la Vue Partielle.
La méthode render :partial offre de nombreuses options que nous ne verrons pas ici, notamment la possibilité de passer d’autres variables, voyez ici pour en apprendre davantage.
Ce mécanisme offre plus de souplesse que le précédent, surtout si nous voulons réafficher cette liste d’utilisateurs ailleurs dans le site. Bientôt, nous itérerons sur des collections d’objets en provenance directe de la base de données, et c’est là que nous irons véritablement au bout de cette technique.
Assistants (Helpers)
Les Assistants, ou Helpers en Anglais, sont un moyen d’éviter au maximum que du code opérationnel ne vienne polluer vos Vues. Il s’agit simplement d’extraire au maximum les traitements au niveau de la Vue pour les placer dans des classes Ruby qui sont directement rendues disponibles dans la Vue (mais qui, par défaut, ne le sont plus du Contrôleur, il faut le savoir).
Ainsi imaginons par exemple une méthode qui prend un objet Date, et qui va renvoyer l’âge du membre. Sachant que cette méthode concerne essentiellement les utilisateurs, nous allons donc naturellement la placer dans le fichier app/helpers/utilisateurs_helper.rb :
Ainsi nous pourrons utiliser la méthode calculer_age dans la Vue. Vous remarquerez qu’il ne s’agit pas ici d’une classe, mais d’un module. La différence est pour nous très légère, mais elle est liée à une des forces de la programmation Ruby, les Mixins, qui permettent d’ajouter faciler des comportements supplémentaire à une classe tout en restant plus souple qu’un héritage classique (multiple ou simple). Ainsi le module UtilisateursHelpers est-il mixé dans la classe qui s’occupe de la Vue.
Voilà donc le code de notre Vue Partielle modifiée pour tirer profit de cette nouvelle méthode que nous venons d’implémenter :
Squelettes (Layout)
Les Squelettes ne sont pas exactement une spécificité de Rails, mais leur implémentation mérite d’être commentée. En somme il s’agit d’une Vue contenant une invocation de la méthode yield à l’endroit où l’on souhaite afficher le contenu de la page en cours. On les place habituellement dans le répertoire app/views/layouts/.
Ajoutons donc le fichier standard.html.erb dans ce même répertoire et créons une page web très rudimentaire, mais qui fera notre affaire dans un premier temps.
Et voilà ! Reste maintenant à indiquer à Rails que nous souhaitons que toutes les pages qu’il va afficher utilisent ce Squelette. Puisque cette disposition concerne toutes les pages de notre site, nous allons tout naturellement compléter notre Contrôleur Application (app/controllers/application.rb) :
Maintenant modifions notre page d’accueil (app/views/accueil/index.html.erb) en éliminant le superflu :
L’utilisation d’un Squelette nous permet donc d’éviter la répétition inutile de code d’action en action. Bien entendu, vous pouvez choisir de désactiver son utilisation pour une action donnée, en utilisant la méthode render que nous avons vue précédemment avec les Vues Partielles. Voiçi par exemple ce que nous pourrions faire pour que la page d’accueil ne l’utilise plus :
Utilisation des Flashes et de Content_for
Les Flashes
Vous aurez sans doute besoin d’afficher des informations de feedback à l’internaute, par exemple pour lui signaler que son compte a bien été créé, qu’une erreur s’est produite, qu’il est bien connecté/déconnecté, etc. Rails met pour cela à votre disposition les Flashes.
Typiquement, il s’agit d’un simple tableau associatif qui peut contenir ce que vous souhaitez - sa particularité est sa durée de vie, qui est très brève : il va être passé à l’action suivante avant de disparaître . Pratique donc pour afficher des messages ponctuels.
Pour cela il nous faut prévoir l’endroit où Rails va les placer, s’il en trouve. Généralement, c’est une bonne idée de placer ça dans votre Squelette un peu avant le yield. Éditons donc notre fichier app/views/layouts/standard.html.erb en conséquence.
Cet extrait de code va nous permettre de boucler sur les différents éléments du Hash des Flashes, en récupérant à chaque fois l’indice (key) et la valeur (msg). Pour chaque itération, on crée un div dont le contenu est le message et qui a pour attribut id la valeur de l’indice du tableau. Cela va nous permettre de faire facilement évoluer notre site, si nous avons besoin de nouveaux type de notification, etc.
Le reste n’est plus qu’une affaire de CSS : à vous de donner un fond vert aux notifications de succès, un fond bleu pour les informations et un fond rouge pour les erreurs, par exemple. Voilà le lien pour la documentation officielle qui vous en apprendra plus au sujet des Flashes.
Content_for, du contenu modulaire
L’intérêt de content_for et de vous permettre de créer du contenu modulaire qui sera plus lié à la Vue qu’au Contrôleur. Cela peut sembler un peu complexe, mais l’intérêt deviendra clair avec les deux exemples que je vais vous fournir. Tout d’abord, imaginons que nous souhaitions ajouter une feuille de style particulière à une ou deux pages particulières.
Nous pourrions tout simplement ouvrir une balise link au beau milieu de notre vue et le tour serait joué - mais puisque nous utilisons un Squelette, notre lien serait obligatoirement dans le body ce qui est parfaitement incorrect du point de vue des spécifications HTML. Pour contourner cela, procédons en deux temps : tout d’abord, nous allons éditer le fichier de Squelette en y ajoutant une sorte de « point d’entrée » que nous pourrons remplir à notre convenance dans n’importe quelle Vue.
Vous remarquerez que nous invoquons ici la même méthode que pour afficher le contenu de la Vue en cours, le mot-clé yield, en y ajoutant un symbole pour l’identifier, :entete(je n’ai pas encore parlé des symboles, qui sont une spécificité de Ruby, il s’agit d’une sorte de variable que vous apprendrez à connaître au fur et à mesure de votre pratique).
Maintenant, nous pouvons spécifier à l’endroit de notre choix le contenu pour (content_for) remplir ce point d’entrée, et nous allons faire cela dans la vue de la page d’accueil (app/views/index.html.erb) :
Le contenu sera ainsi placé au bon endroit par Rails quand nous arriverons sur cette page : le tour est joué. Vous remarquerez ici que je fais usage de deux Assistants que nous fournis Rails et qu’il est utile de connaître : le premier permet de charger une feuille de style que vous placerez dans le répertoire public/stylesheets/ et l’autre un script placé dans le répertoire public/javascripts/. Apprenez tout sur ces Assistants à la page suivante !
Voilà une autre utilisation de cet Assistant : comment changer le titre de la page en cours de façon dynamique ? Une mauvaise idée (je l’ai eue, c’est pour ça que je sais qu’elle est mauvaise ;)) pourrait être d’utiliser une variable d’instance @titre_page qu’on afficherait dans le Squelette au bon endroit. En pratique, c’est très problématique, car il arrive souvent que l’on choisisse de "rendre" une Vue depuis une autre action que celle où vous avez déclaré la variable au départ (dans le cas d’une validation de formulaire, par exemple).
Voilà donc la bonne façon de faire, vous remarquerez que le principe est très similaire : éditons d’abord le fichier du Squelette pour le rendre modulable (app/views/layouts/standard.html.erb) :
Comme vous pouvez le constater, j’ai ajouté un nouveau yield : il ne reste plus qu’à insérer le contenu que nous souhaitons dans la Vue de la page d’accueil du site comme suit (app/views/accueil/index.html.erb).
<%= yield :titre_page %>
-
<%= render :partial => ’utilisateurs/utilisateur’, :collection => @utilisateurs %>
Deux choses apparaissent ici : le titre de la Vue est maintenant bien présent dans la barre de titre du navigateur, ce qui est une bonne chose - mais j’ai en plus de ça évité la répétition du titre en utilisant une nouvelle fois l’instruction yield dans le h1, ce qui est aussi une bonne chose.
Conclusion
Je pensais au départ vous guider dans la création d’un système rudimentaire d’authentification, mais il me semble que c’est une mauvaise idée et que sans connaître le Modèle, nous ne pouvons encore rien faire de très intéressant avec Ruby on Rails ... On se réserve donc pour le prochain article ;) !
J’espère en tous cas que cet article vous aura donné des idées pour expérimenter avec Rails, voir un peu où se trouvent les fichiers importants, etc. En guise de conclusion, je voudrais revenir sur le fait que j’ai souvent fait référence à la documentation (ou plutôt l’API) du framework : il s’avère que contrairement à beaucoup d’autres de ses collègues, Rails est remarquablement bien documenté dans sa documentation officielle qui est toujours à jour et fournit généralement la totalité des informations nécessaire.
Cependant, ce qui peut prendre un peu de temps est de savoir comment bien faire les choses avec Rails. Et pour ça, la documentation officielle ne vous sera pas d’un grand secours ... De manière générale, le site railscasts.com entretenu par Ryan Bates est une excellente source d’information - les plus connaisseurs d’entre-vous auront peut être repéré des emprunts que j’ai fait ici à ses screencasts ;) ... Je ne saurais trop vous recommander d’aller y faire un tour.
Dandelionmood.com a déménagé !
Pour éviter la prolifération du spam, j'ai préféré désactiver les commentaires, d'autant que ce site n'est plus actif ... Merci à vous si vous aviez commenté, à bientôt sur Choses à faire.fr ;) !
