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!

Aucun commentaire: