Des contrĂŽleurs optionnels grĂące Ă const_missing !
Ah les contrÎleurs, mieux ils sont fait, plus nombreux, semblables et inutiles ils seront. Ne gagnerait-on donc pas à gommer leurs ressemblances et les rendre optionnels ?
Mais quâest-ce quâun bon contrĂŽleur ?
Quand cette question est soulevĂ©e, lâadage skinny controllers, fat models surgit. Moi je dirais optionnal controllers, object-oriented models.
Avant tout, le bon controlleur doit respecter le cadre logiciel dans lequel il Ă©volue. Ruby on Rails a fait le choix de populariser le style dâarchitecture REST, qui consiste Ă considĂ©rer ce quâon dĂ©livre via son application comme des reprĂ©sentations de ressources avec lesquelles on peut interagir Ă lâaide de verbes dĂ©finies par le protocole HTTP. Un controlleur ne doit donc exposer quâune liste restreinte dâactions qui correspondent aux verbes qui permettent dâinteragir avec ces ressources.
En ce sens, lâensemble des contrĂŽleurs constitue lâinterface visible dâune application qui sâexprime en ressources.
Quâest-ce quâune ressource ?
Ces ressources tendent Ă se confondre avec les modĂšles, mais cela sâavĂšre vite trompeur. Car si vous y restreignez votre application, vous finirez bien vite par ajouter des actions supplĂ©mentaires Ă vos contrĂŽleurs, violant ainsi les prĂ©ceptes de REST.
Prenons le classique modĂšle User ! Si vous nây voyez quâune seule ressource, vous allez devoir ajouter des actions register, confirm_email, change_password, reset_password, confirm_reset_password alors que si vous considĂ©rez le mot de passe comme une resource, et lâinscription (registration) comme une autre, le tout sâemboite joliment dans des contrĂŽleurs sĂ©parĂ©s faciles Ă Ă©crire. Ou Ă âabstracterâ comme nous verrons dans le reste de lâarticle !
Réalisation
Voici ce Ă quoi peut ressembler un contrĂŽleur type (une version rĂ©duite Ă lâessentiel dâun scaffold)
CODE
Nous pouvons assez facilement le rendre gĂ©nĂ©rique et en faire hĂ©riter dâautres contrĂŽleurs.
CODE
Dans la mĂ©thode resource_class , nous dĂ©tectons en fonction du nom du contrĂŽleur en cours (celui qui hĂ©rite de resources_controller) le nom de la classe associĂ©e et nous lâutilisons dans les diffĂ©rentes actions
Nous pouvons dÚs lors écrire des contrÎleurs vides, qui ne contiennent que la déclaration :
CODE
Mais ce travail a dĂ©jĂ Ă©tĂ© fait, avec brio, sur tout le gem inherited_resources que nous utiliserons plus tard sâil est utilisĂ© par lâapplication.
Nây aurait-il pas un moyen de se dĂ©barrasser de cette dĂ©claration vide ?
Si, il y a const_missing!
Vous connaissez certainement method_missing, la mĂ©thode qui sâexĂ©cute quand un objet reçoit un message auquel il ne sait rĂ©pondre, ni lui ni ses ancĂȘtres dans la hiĂ©rarchie de classes.
const_missing est son corolaire pour les constantes, mais joue un rĂŽle important : celui du chargement de classes. Nous verrons cela en dĂ©tail dans la derniĂšre partie de lâarticle. Concentrons-nous sur const_missing.
Cette fonction peut ĂȘtre dĂ©finie au niveau des modules mais vous voulons dans notre cas la rendre globale. Câest donc dans la class Object que nous allons la dĂ©finir en tant que mĂ©thode de classe.
CODE
Nous limitons notre intervention aux seuls noms de classes qui finissent par Controller et mĂȘme dans ce cas-lĂ nous donnons une chance Ă lâautoload (voir ci-aprĂšs) dans le cas oĂč le contrĂŽleur existe, mais nâa juste pas encore Ă©tĂ© chargĂ©.
CODE
Nous pouvons alors définir notre contrÎleur tout en nous assurant que le modÚle correspondant existe. Faisons cela dans la classe MissingController proprement dite :
CODE
CODE
Thatâs it ! Il ne nous reste maintenant quâĂ donner vie Ă ces contrĂŽleurs via les routes. Vous pouvez limiter les actions exposĂ©es via lâattribute only:
CODE
const_missing et autoload
const_missing est la pierre angulaire du mĂ©canisme dâautoload, qui rend les classes de notre code disponibles partout sans le moindre require. Ruby embarque autoload que Ruby on Rails amĂ©liore pour permettre le chargement de classes au runtime et de dĂ©finir diffĂ©rents paths (emplacements) dâoĂč pourront ĂȘtre chargĂ©es les classes.
Le mĂ©canisme de recherche de constantes en Ruby suit des rĂšgles simples pour dĂ©terminer lâemplacement de la bonne constante Ă utiliser Ă un endroit donnĂ© de votre code. Ce mĂ©canisme repose sur la mĂ©thode Module.nesting qui renvoie le niveau dâimbrication de modules oĂč elle est appelĂ©e. Votre constante est recherchĂ©e au sein de ces modules, ou dans les ancĂȘtres du premier module (Module.nesting.first.ancestors) ou dans les ancĂȘtres de object (Object.ancestors)
Si aucun de ces emplacements ne contient la constate convoitĂ©e, le processus dâautoload (chargement automatique de constante) est dĂ©clenchĂ©.














