Les associations dans Rails - a podcast by Sylvain Abélard

from 2016-03-06T14:45

:: ::

Bonjour, voici l’épisode 7, sur les associations dans Rails.
Il fait suite à l’épisode 6, où je vous recommande de toujoursconsidérer la cardinalité de ce dont vous parlez : 0, 1 ou N.

En pratique c’est aussi ce que vous trouverez dans un diagramme
UML ou dans vos bases de données : associations 1 à 0 ou 1, 1 à 1,1 à N et N à N. Plus qu’un épisode de métaphore, c’est un épisode
qui sert de “pont” entre trois domaines : UML, SQL relationnel,et ActiveRecord qui est l’ORM de Ruby on Rails.

Là encore, il y a une introduction à Rails et ActiveRecord
dansl’épisode 3 sur les requêtes N+1,
que je vous recommande si vous êtes perdus.

Le cas de l’association

L’ORM, c’est la correspondance entre des objets Ruby et des
données dans une base de données.

On fait une correspondance entre une table et une classe,
un champ dans une table et une propriété de l’objet,et un enregistrements de la table avec une instance d’objet.

L’enjeu de la modélisation objet est de représenter un
modèle pratique et utilisable de la réalité (à défautd’être exact), et une des méthodes les plus connues (je ne
dis pas les seules ni que la norme précise est respectée)est le diagramme de classes de la norme UML.

Quant aux bases de données relationnelles, elles sont
souvent représentées par quelque chose approchant lesdiagrammes entité-relations, les MCD de Merise ou plus
simplement… les schémas de bases de données.

Dans Ruby on Rails également, on a la possibilité dedécrire des associations entre objets.

Note sur l’anglaisJe parlerai de code en anglais avec un énorme accent français,
parce que ça fait une différence entre le code et le commentaire ;pour retrouver les mêmes mots dans mes exemples que dans la
documentation ou sur StackOverflow, et parce que le code Ruby et Railsest presque aussi facile à lire que des phrases anglaises.

On peut débattre de “faut-il coder en français ou en anglais”,
mais mon but n’est pas de vous forcer à faire quoi que ce soit :dans votre équipe, dans votre projet, trouvez votre propre équilibre.

Has Many

L’association 1-N, que Rails nomme Has Many.
Par exemple, un panier a beaucoup d’articles :Cart Has Many Articles.

À l’inverse, un article ne peut être que dans un seul panier.
C’est l’association Belongs To :Articles Belongs To Cart.

En base de données, ActiveRecord s’attend à trouver la colonnecart_iddans la tablearticles, et uniddans la tablecarts.
Vous pouvez sortir de ces conventions, mais lisez bien la docd’ActiveRecord pour apprendre à le faire proprement.

ActiveRecord vous donnera plein de méthodes utiles :cart.articlespour avoir un tableau des articles du panier,cart.articles=pour enregistrer ces articles dans le panier,cart.article_idspour les identifiants.

De l’autre côté,article.cart,article.cart=,article.cart_id.

Note sur l’enregistrement

Attention, il est important de noter que tout ce que vous faites ici
c’est travailler sur des objets Ruby. Rien n’est enregistré.Il y a trois étapes :

  • aller chercher les données en base et en faire des objetsavec un where, find, ou une méthode d’accès comme@cart.goods

  • travailler sur lesdits objetsavec tous les traitements Ruby et Rails que vous voulez

  • enregistrer tout cela dans la base de donnéessi vous avez fait des changements, il faut les sauvegarder

Si vous modifiez des objets Ruby, tant que vous n’avez pas sauvé
vos objets Ruby en base, seul le bout de code qui est allé leschercher (et les bouts de code auxquels il les a donnés) sont au
courant des modifications. Si quelqu’un d’autre va chercher lesinfos en base, il ne voit pas les changements.

HABTM

Il y a aussi l’association N-N, que Rails nomme
Has And Belongs To Many, HABTM pour faire court.

Par exemple, une personne peut posséder plusieurs logements.
Vous pouvez n’être propriétaire de rien du tout ([]),
d’un seul ([:home]), et certains peuvent en avoir énormément
([:home, :beach_house, :ski_house, :fishing_house]).

Mais si votre client souhaite pouvoir noter qu’une maison a
plusieurs propriétaires, et non un seul, 1-N (Has Many) ne suffit pas.Il faut passer à N-N (HABTM).

La table Owner ne contient pas d’ID de House
(sur un formulaire papier, on écrirait maison 1, maison 2, maison 3….impossible de savoir combien on devrait en prévoir, et que d’espace
gaspillé !), pas plus que la table House ne contient d’ID de Owner.

Mais il y aura en BDD une table dite de jointure, parce qu’elle
fait le lien entre les données des deux tables.Rails l’appelleraHouses_Owners, et cette table contiendra une cléhouse_idet une cléowner_idcontenant les identifiants
respectifs de House et Owner.Il y aura ensuite autant d’enregistrement que de
“liens de possession” entre une maison et un propriétaire.

Les méthodes utiles seront les mêmes,owner.houses,owner.houses=,owner.house_idset réciproquementhouse.owners,house.owners=ethouse.owner_ids.

Has-Many Through

Mais on sait seulement qu’il y a un lien ! On n’a pas d’information
sur la nature ou les conditions de ce lien.Si vous voulez que cette association porte des informations, l’idée
de la jointure est bonne. Poussons-la plus loin.

Faites un objet qui relie les deux et dans lequel vous rangez les
informations de ladite relation, puis des Has-Many vers cet objet.

Par exemple pour une location de voiturePerson Has Many RentalsetCar Has Many Rentals. Ainsi chaque Rental sait retrouver
la bonne voiture, son locataire, et tout ce que vous voudriezajouter, comme : les dates et heures de début et fin de location,
le prix appliqué, des infos variées etc.

Rails proposera un dernier confort dans ce cas, les Has Many Through,
iciPerson Has Many Cars Through Rentals, qui veut dire
“on peut retrouver toutes les voitures d’un client,à condition d’aller les chercher à travers son historique de locations”,
et vous pourrez alors avoir les deux méthodes utilesperson.carsetperson.car_idsà disposition.
Je ne pourrais pas vous donner deperson.cars=car il faudrait
alors renseigner tous les objets Rental entre deux.

Has-One

Enfin, je vous mets en garde contre les associations 1-1,
qui sont toujours techniquement possibles, mais qui sont pour moiassez rares.

En tout cas, c’est signe qu’il y a une question à poser :
on veut dire “un chien a un maître”,Dog Has One Master
mais en réalitéDog Belongs To Master,
car un maître peut avoir plusieurs chiens (là encore, 0, 1 ou N chiens)mais un chien ne peut pas avoir plusieurs maîtres.

Enfin, c’est possible dans la vraie vie et mais si c’était le cas,
vous n’auriez pas tenté d’écrire “un chien A UN maître”.

D’autre part parce que si les informations sont si “couplées” etdoivent aller la main dans la main, pourquoi ne pas tout mettre dans
la même table ? Si un client peut avoir plusieurs mails, que certainesboîtes mail peuvent être partagées… on ne se pose aucune question,
on laisse dans la même table email et nom du client.

Mais quand vous avez un souci avec un Has One, je pense qu’en général
il y aura une évolution un jour pour le transformer en Has Many :Customer Has One Addressdeviendra probablementCustomer Has Many AddressesPhoneNumber Has One CustomerplutôtCustomer Has Many PhoneNumbers

Si vous êtes toujours coincés, voici mon astuce, demandez-vous :
“puis-je avoir l’un sans l’autre ?”

Une adresse sans maison a du sens (terrain vide),
une adresse avec plusieurs maisons a du sens (appartements),une maison sans adresse n’a pas de sens (on l’a bien construite quelque part),
une maison avec plusieurs adresses est possible mais rare (coins de rues).

Ainsi, on part surAddress Has One House, ce qui était probablement
l’inverse de ce que vous vous attendiez à écrire dans un raisonnementclassique. En tout cas, j’avais pris l’exemple au hasard et
la conclusion m’a surpris moi-même.

Further episodes of Zen M-4 : Zen Metaphor

Further podcasts by Sylvain Abélard

Website of Sylvain Abélard