Affichage des articles dont le libellé est factorisation. Afficher tous les articles
Affichage des articles dont le libellé est factorisation. Afficher tous les articles

vendredi 30 octobre 2009

Rails: contourner un problème par l'utilisation de la méthode send.


Dans le cadre d'utilisation d'association de type 'belongs_to' avec clés étrangères absentes.


Comment par simple baquette magique remplacer une dizaine de blocs identiques par un petit bloc de 4 lignes ?














Voici l'exposé du problème :j'ai une table principale Projet qui utilise plusieurs clés étrangères pour afficher des libellés .

class Projet < ActiveRecord::Base
belongs_to :moe
belongs_to :moa
belongs_to :domaine
belongs_to :techno
belongs_to :filiere
belongs_to :didev
belongs_to :diprod


Parfois, la clé étrangère n'est pas renseignée et cela provoque une erreur dans l'affichage de l'objet principal. Ce cas arrive pour ma part, principalement dans deux situations:


  • En phase de développement: je n'ai pas encore finalisé les écrans permettant de rattacher la table principale avec ses tables associées (à faire sous forme de liste déroulantes)
  • Par choix fonctionnel, la valeur ne doit etre servie. Dans ce cas, il est toujours possible d'ajouter une entrée factice dans la table (non satisfaisant)
La solution 'brute' consiste à tester avant d'afficher la validité de la clé étrangère , et de répéter ce test tout le long de la vue.
Dans l'illustration suivante, je montre comment factoriser son code :
(cliquez sur l'image pour agrandir)


L'astuce consiste à remplacer l'appel d'une méthode par l'envoi d'un message à la methode 'send' de l'objet.

Dans cet exemple, j'appelle une fonction avec trois paramètres:
L'objet (projet)
Le nom de la classe decrivant les libellés (nom de la table au singulier)
L'attribut à afficher
Je procède à un appel imbriqué de méthode.





Ces trois formes d'appel produisent le même résultat :
  • mon_projet.methode
  • mon_projet.send('methode')
  • mon_projet.send(:methode)
Dans le cas présent, en raison de l'utilisation d'une clé étrangère je suis obligé de passer par une syntaxe imbriquée:
mon_projet.send('objet_libelle').send('attribut_a_afficher')

Et en bonus, comment afficher une liste déroulante à partir d'un table libellé ?

Par une simple ligne :
<%= select(:projet, "domaine_id", Domaine.find(:all).collect {|p| [ p.libelle, p.id ] }, :include_blank => true) %>

Good hacking!

mercredi 28 octobre 2009

Les modèles gros contre les maigres


Le titre est racoleur comme cette illustration que j'ai volontairement floutée.
(L'originale est disponible sur google image)

Rails est un framework MVC : modele/view/controleur

La philosophie de Rails est aussi dans la re-factorisation du code, de manière à éviter d'avoir des gros contrôleurs. Ce défaut est source de toutes les difficultés : maintenance , réutilisation du code et évolution de l'application.


J'illustre mon propos par un exemple de projet qui gère un portefeuille applicatif. Ces applications sont de différentes technologies ,et on doit pouvoir filtre les applications sur leur type de technologie :









Dans une première version , jamais mis en dur dans le contrôleur les options de filtre possible.

Après modifications , j'arrive à :
Un modèle plus 'gros':


Ce modèle contient toute la logique de sélection (Select SQL)
Il ne faut pas hésiter à faire des méthodes 'find' taillées sur mesure.











Le contrôleur:


Le contrôleur est allégé pour ne contenir que la partie 'métier' du traitement. Dans cette solution , non seulement les tests 'en dur' ont disparus mais en plus l'ajout d'une nouvelle catégorie ne nécessitera aucune modification de code.








La vue est elle aussi simplifiée:

D'une manière générale, il faut éviter de mettre trop de traitement dans les vues. Cela rend l'application, très difficile à maintenir et le code inséré dans les vues est assez contraignant à écrire.












Où se trouve alors tout le traitement qui génère l'affichage de la console de bouton radio ? . Car malheureusement, il faut bien qu'a un moment donné une méthode prenne en charge :
a) Afficher toutes les options
b) Pré-selection de l'option 'cochée'.
Cette méthode va etre placée dans les 'helpers' de l'application qui prendra cette forme:


Je n'ai pas forcement le bon style d'écriture du code. Ici on fabrique le HTML utile pour les boutons radio.
Cette méthode n'est possible que parce ma liste des options était contenue dans une table.






En résumé : toujours re-factoriser son code : DRY : don't Repeat Yourself ou Duplication is Evil . Dans mon exemple la logique de la gestion des options est dans le helper et que dans lui. Le resultat donne un système qui evoluera sans modification à apporter au code.
En conclusion je me pose la question suivante : Pourquoi doit on re-factoriser dans les langages proceduraux et ne pas le faire dans les langages fonctionnels ?.