playlist Ajout de validations

Publié il y a 9 mois dans la série : Rails
Nicolas Cavigneaux
Votre formateur
Nicolas Cavigneaux

A la recherche d'un langage polyvalent, j'ai fait la découverte de Ruby en 2003. J'ai donc très vite commencé à utiliser Ruby au quotidien pour des tâches diverses et variées (scripting, applications lourdes…).

Courant 2004, une vague de fraicheur est apparue avec l'arrivée de Ruby on Rails qui m'a de suite conquis. J'ai donc décidé de participer activement à la communauté (forums, patches, librairies, …). En 2010, je fais la rencontre de Martin Catty et retrouve dans sa vision la rigueur et les bonnes pratiques que j'aime mettre en place, le déclic a donc été immédiat.

Synbioz met en place des solutions robustes sur la base d'outils modernes et funs, je veux faire partie de l'aventure.

Catégories : Développement

Dans cette vidéo de la série Ruby on Rails, nous allons voir comment ajouter des validations aux modèles de notre application pour la rendre plus robuste.
Afficher le transcript complet de la vidéo
Ajout de validations

Bienvenue dans cette vidéo consacrée à Ruby on Rails. 

Aujourd'hui nous allons améliorer la gestion de nos produits d'un point de vue métier. Jusqu'à maintenant on pouvait créer nos produits sans respecter aucune règle puisqu'aucune vérification n'est en place.

On peut donc créer un produit sans nom, avec un prix négatif, sans image, etc.

Heureusement Rails met à notre disposition l'outillage nécessaire pour mettre facilement en place des contraintes métier sur les modèles, on appelle ça les validations.

En Rails la mise en place de validations se passe donc dans le modèle nous allons donc ouvrir le fichier app/models/product.rb.

C'est pour le moment une classe vide qui hérite simplement de ApplicationRecord ce qui lui permet de se comporter comme un modèle et de pouvoir accéder aux informations en base de données.

Validation de présence

Ajoutons nos premières validations qui vont consister à s'assurer que le produit contiennent bien un titre, une description et une image.

validates :title, :description, :image_url, presence: true

On utilise donc la méthode validates qui permet de vérifier qu'un ou plusieurs champs respectent une ou plusieurs conditions. Ici on a simplement précisé que la présence était requise. Les attributs correspondants doivent donc être présent et non-vides.

Démonstration de remontée des erreurs sur la page formulaire

Voyons ce que ça donne dans le formulaire.

Si on essaie de créer un produit sans remplir ces trois informations, la validation nous empêche de le faire et notre formulaire est rendu à nouveau en mettant en évidence les erreurs grâce à une liste récapitulative des erreurs et un contour rouge autour des champs concernés.

C'est le style par défaut généré par le scaffold que nous avons utilisé lors de la mise en place de la gestion des produits.

Si on regarde le fichier app/views/products/_form.html.erb on voit qu'il y un bloc conditionnel dédié à l'affichage du récapitulatif d'erreurs s'il y en a.

Pour la mise en évidence des champs concernés, ce sont les helpers de form, ici label, text_field et text_area qui ajoute un div avec une classe field_with_error autour du champ lorsque ce dernier est en erreur.

Validation du prix

Passons maintenant à l'ajout des validations pour le prix. Disons pour l'exemple qu'on souhaite n'autoriser que des prix qui sont supérieurs ou égaux à 1.

validates :price, numericality: { greater_than_or_equal_to: 1 }

On sauvegarde et on va à nouveau tenter de créer un produit. Tout d'abord en passant une chaîne plutôt qu'un chiffre.

Dans ce cas, la validation nous empêche la création en nous disant que le prix n'est pas un chiffre, parfait.

Essayons maintenant avec un chiffre négatif.

Une fois encore la création est rejetée en nous disant que la valeur doit être égale ou supérieure à 1.

Validation d'unicité du titre

On peut passer à la suite ! On va maintenant s'assurer que le titre de notre produit est unique pour éviter qu'on puisse en confondre deux.

On retourne donc dans notre modèle pour ajouter une validation d'unicité :

validates :title, uniqueness: { case_sensitive: false }

On essaie de créer un nouveau produit portant le nom "foo".

La validation nous empêche de le faire en nous disant que ce nom est déjà pris.

Vous aurez sûrement noté que plutôt que de simplement passer true à la clé uniqueness, j'ai passé un hash d'option qui contient case_sensitive à false.

J'ai fait ça pour qu'il ne soit pas possible de créer un produit ayant le même nom mais avec une casse différente. D'ailleurs le produit qu'on a essayé de créer ne contient pas de majuscule contrairement au produit existant. Sans cette option, le produit aurait été valide et enregistré en base.

Validation du format de l'image

Nous sommes presque arrivés au bout, on n'a pour le moment prêté aucune attention particulière à l'attribut image_url. Il faudrait pourtant vérifier que ce qui est passé semble bien être une image. Ce n'est pas une solution sans faille mais nous allons faire ça en vérifiant que le nom qui est passé fini bien par .jpg, .png ou .gif :

validates :image_url,
  format: {
    with: /\.(jpg|png|gif)\z/i,
    message: 'doit être au format jpg, png ou gif'
  },
  allow_blank: true

C'est de loin la validation la plus compliquée que nous avons mise en place jusque là. Voyons en détails ce qu'elle fait.

Pour commencer, on utilise l'option format pour signifier qu'on va vouloir vérifier le format de ce qui est contenu dans l'attribut image_url. Dans ce format, nous utilisons l'option with qui s'attend à recevoir une expression rationnelle. On lui en passe donc une qui dit qu'on veut que image_url contienne un point suivi d'une des chaînes jpg, png ou gif. Tout ça en bout de chaîne grâce à l'ancre \z. Pour finir on passe l'option i à notre expression pour dire qu'on veut que la comparaison soit insensible à la casse ce qui permet à l'utilisateur de passer une URL où l'extension serait en majuscules.

Si vous n'êtes pas à l'aise avec les expressions rationnelles, n'hésitez pas à regarder la vidéo dédiée aux expressions rationnelles en Ruby disponible sur Hackademy.

On passe ensuite une deuxième option qui est message. Ça n'a rien d'obligatoire mais le message par défaut pour un problème de format est "is invalid" ce qui ne va pas vraiment aider notre utilisateur à comprendre pourquoi ça ne fonctionne pas. On remplace donc ça par un message plus informatif.

Finalement et ça doit certainement vous étonner, on autorise à ce que la valeur soit vide. Pourquoi donc ? Tout simplement parce que si l'utilisateur ne renseigne pas le champ, on aura une double erreur de validation qui va s'afficher, une pour l'absence de valeur et une pour le défaut de format. En autorisant ici une valeur vide, si l'utilisateur n'entre rien, on n'aura que le message de validation indiquant l'absence de valeur. S'il entre ensuite une valeur mais non valide, on aura bien le message d'erreur relatif au format et lui seul.

Une solution alternative aurait été de supprimer la validation de présence sur image_url et ne pas mettre le allow_blank. Dans ce cas, que l'attribut soit absent ou qu'il ait un mauvais format, l'erreur de validation affichée serait toujours celle qui dit que le format est invalide.

On a donc rendu notre formulaire de gestion des produits plus robuste grâce à l'ajoute de seulement quelques lignes de code dans le modèle.

Dans le prochain épisode nous commencerons à nous attaquer aux tests automatisés qui nous permettront de valider que notre code fonctionne comme attendu et également d'avancer de manière plus sereine en étant certain de ne rien casser dans l'existant au fil de nos développements.

À bientôt !
3/9 dans la sérieRails