Choses à faire

24h dans une journée, et tant de choses à faire !

La couche Modèle de Rails (Partie 3)

publié le 10 janvier 2010 par Pierre Quillery

Aujourd’hui, je me propose d’achever cette série par quelques explications concernant les fichiers de garniture (aussi appelés fixtures) ainsi que l’utilisation des filtres (on parle de named scope) pour faciliter la sélection de données.

Cet article fait partie d’une série sur le framework Ruby on Rails dont vous pouvez consulter le plan sur mon ancien site.

Il est également le dernier de la série de trois articles que j’ai publié sur l’implémentation de la couche Modèle de Ruby on Rails. Vous pouvez lire le premier article ou le second, si vous ne l’avez pas fait.

Les filtres (named_scope)

Ces filtres sont à mon avis une fonctionnalité très intéressante de Rails : ils permettent d’ajouter simplement un jeu de critères nommé à une requête SQL. Si on traduit le terme Anglais, il s’agit littéralement de « points de vue nommés » ; ce n’est pas très explicite, et c’est pourquoi je préfère le terme de « filtre » – il ne faut cependant pas les confondre avec les filtres de Contrôleur dont je parlais dans un précédent article.

Par exemple, imaginons que nous avons à notre disposition un magasin en ligne qui souhaite mettre en avant les produits qui sont les moins chers (dont le prix est entre 1 et 5 euros par exemple). Nous pourrions être tentés d’écrire ceci, par exemple :

Articles.find :all, :conditions => { :prix => [ 0 .. 5 ] }

Notez la syntaxe [ ... ], elle permet de spécifier un intervale de valeurs. L’inconvénient de cette façon de faire c’est que si par la suite nous voulons ajouter d’autres crtières de sélection (uniquement les articles de telle catégorie, uniquement ceux qui sont soldées, dont la date de péremption expire bientôt, etc.) nous allons devoir dupliquer ce critère … De plus, si notre client décide d’agrandir la gamme de prix, nous serions obligés de repasser sur tout notre code en risquant d’oublier quelque chose.

Nous pourrions bien sûr utiliser des constantes, ou des variables de classe, mais ça rendrait l’écriture de nos conditions encore plus longues et moins explicite – c’est là qu’interviennent les named_scope. Éditons la classe Article pour ajouter un filtre :

class Article < ActiveRecord::Base
  named_scode :pas_chers, :conditions => { :prix => [ 0 .. 5 ] }
end

Pour l’instant, nous n’avons fait que déplacer un peu de code du Contrôleur vers le Modèle, rien de transcendant – mais voilà ce que nous pouvons maintenant écrire :

@articles = Article.pas_chers.find :all, :conditions => { :rubrique_id => 2 }

Et voilà le travail : nous pouvons réutiliser et même chaîner des jeux de critères de sélection ! Attention toutefois à ne pas en abuser, même si c’est assez tentant : cela a un impact sur les performances qui doit rester maîtrisé.

Pour en savoir plus, je vous renvoie à la documentation de la méthode sur l’API ainsi qu’à un épisode des Railscasts de Ryan Bates (en Anglais).

Les fichiers de garniture (fixtures)

Les fichiers de garniture permettent d’ajouter facilement des données de test à votre application et vont donc en faciliter le développement : leur écriture peut se faire sous forme de fichier yaml ou csv. La première forme est la plus intéressante, car elle s’intègre mieux à Rails et permet même d’utiliser directement les mécanismes de relations entre les classes Modèles que nous voyions dans un précédent article.

Concrètement, tout se passe dans les fichiers qui sont générés automatiquement quand vous créez des Modèles à l’aide de la commande script/generate model .... Regardez dans le répertoire test/fixtures pour les retrouver. En reprenant l’exemple des classes que nous voyions dans l’article précédent, vous devriez ainsi trouver les fichiers articles.yml, taggables.yml, tags.yml et utilisateurs.yml.

Ouvrons dans un premier temps le premier fichier, articles.yml :

one:
  login: MyString
  mot_de_passe: MyString

two:
  login: MyString
  mot_de_passe: MyString

Comme vous pouvez le voir, le fait d’utiliser le générateur pour créer la classe de modèle Utilisateur a également eu pour effet de générer deux entrées dans ce fichier en renseignant directement les noms des colonnes que nous avions spécifié.

Notez également que chaque enregistrement possède déjà un identifiant (one et two) qui nous permettra d’y faire référence dans un autre fichier pour créer une relation !

Modifions un peu ce fichier pour créer des Utilisateur plus intéressants :

pierre:  
  login: pierre
  mot_de_passe: mdp1

killian:
  login: killian
  mot_de_passe: mdp2

georges:
  login: georges
  mot_de_passe: mdp3

Nous pouvons maintenant utiliser chacun de ces enregistrements dans la garniture de la classe Article ! Ouvrons donc le fichier articles.yml :

one:
  titre: MyString
  contenu: MyText
  utilisateur_id: 1

two:
  titre: MyString
  contenu: MyText
  utilisateur_id: 1

Rails nous propose de changer la valeur de la colonne utilisateur_id, ce qui est tout à fait possible – cependant, puisque nous avons déjà défini des relations entre ces deux classes, nous allons pouvoir nous passer de cette étape et réécrire le contenu de ce fichier de la façon suivante :

article1:
  titre: "Mon premier article"
  contenu: "Contenu de mon premier article" 
  utilisateur: pierre

article2:
  titre: "Mon deuxième article"
  contenu: "Contenu de mon deuxième article"
  utilisateur: killian

article3:
  titre: "Mon troisième article"
  contenu: "Contenu de mon troisième article"
  utilisateur: pierre

Rails comprendra tout seul que l’utilisateur pierre auquel nous faisons référence a été défini dans le fichier utilisateurs.yml.

Nous pouvons maintenant vider notre base de développement (rake db:reset)pour la remplir avec ces quelques enregistrements, à l’aide de la commande rake db:fixtures:load. Ouvrez maintenant une console Rails, (script/console) et constatez que les enregistrements ont bien été créés dans la base :

>> Utilisateur.find :all
=> [#<Utilisateur id: 134130964, login: "killian", mot_de_passe: "mdp2", 
created_at: "2009-12-23 13:26:49", updated_at: "2009-12-23 13:26:49">, 
#<Utilisateur id: 219077049, login: "georges", mot_de_passe: "mdp3", 
created_at: "2009-12-23 13:26:49", updated_at: "2009-12-23 13:26:49">, 
#<Utilisateur id: 362712307, login: "pierre", mot_de_passe: "mdp1", 
created_at: "2009-12-23 13:26:49", updated_at: "2009-12-23 13:26:49">]

>> Article.find :all
=> [#<Article id: 151089403, titre: "Mon troisième article", 
contenu: "Contenu de mon troisième article", utilisateur_id: 362712307, 
created_at: "2009-12-23 13:26:50", updated_at: "2009-12-23 13:26:50">, 
#<Article id: 655299028, titre: "Mon premier article", 
contenu: "Contenu de mon premier article", utilisateur_id: 362712307,
created_at: "2009-12-23 13:26:50", updated_at: "2009-12-23 13:26:50">, 
.#<Article id: 1040597104, titre: "Mon deuxième article", 
contenu: "Contenu de mon deuxième article", utilisateur_id: 134130964, 
created_at: "2009-12-23 13:26:50", updated_at: "2009-12-23 13:26:50">]

Vous remarquerez que les identifiants des enregistrements créés par ce biais ne commencent jamais par 1, ce qui permet de les distinguer facilement des enregistrements standards et ce qui évitent qu’ils perturbent vos tests manuels.

Si vous voulez tagger un article dans les garnitures, c’est un peu plus sophistiqué, car il faut indiquer à Rails que vous passez par une table intermédiaire à cause de l’utilisation du système has_many :through ; la démarche reste cependant la même : voyez directement dans la documentation pour en apprendre plus.

En guise de conclusion, notez que les fixtures ne sont pas une réponse à toutes les situations. Par exemple, c’est généralement une mauvaise idée de s’en servir pour placer des données nécessaires au bon fonctionnement de l’application : les données que vous y placerez doivent être réservées à vos tests fonctionnels & unitaires.

Si vous avez besoin de mettre en place des données de base pour votre application en production, utilisez le fichier db/seeds.rb. Vous pourrez ensuite exécuter les commandes qu’il contient avec la commande rake db:setup.

La suite au prochain épisode !

Cet article était le dernier de notre série consacrée à la couche Modèle de Rails : aussi dès la semaine prochaine (si tout va bien ;)) nous entamerons une toute nouvelle séquence qui concernera l’implémentation des ressources et des formulaires dans notre framework préféré.

Les textes, illustrations et démonstrations présents sur ce site sont la propriété de leurs auteurs respectifs, sauf mention contraire (photo de la bannière).
Chosesafaire.fr, un site propulsé par Wordpress, vous est proposé par Pierre Quillery & Killian Ebel.

Valid XHTML 1.0 Strict