Skip to content

Les associations en Rails: Partie 07

ubugnu edited this page Feb 4, 2018 · 1 revision

polymorphic

polymorphic est utilisé pour regrouper les associations d'un modèle vers plusieurs autre modèles en une seule association polymorphique. Prenons par exemple le cas d'un simple réseau social: les utilisateurs dans ce réseau peuvent publier:

  • Soit des messages (courts, à la twitter)
  • Soit des articles (formatés)
  • Soit des images

Bien sûr, chaque forme de publication aura son propre modèle. Supposons aussi que les autres utilisateurs peuvent commenter les trois genres de publications, les commentaires auront aussi leur propre modèle.

On va oublier le modèle User bien qu'il soit nécessaire dans un tel cas, car ce qui nous intéresse sont les relations entre les publications et les commentaires.

On se retrouve donc avec quatre modèles: Messages, Articles, Images et Comments, ce dernier devra appartenir à chacun des trois autres modèles.

L'ERD est:

On voit qu'il y a redondance dans la déclaration de belongs_to dans le modèleComment, et qu'il y a trop de clés étrangères dans la table Comments, s'il y avait plus d'entités qui peuvent être commentées ce nombre n'en sera que plus grand.

L'idée est de remarquer que les trois modèles auxquels appartient Comment partagent la même propriété vis-à-vis de leur lien à Comment, à savoir, ils sont commentables! L'idée donc est d'imaginer une classe virtuelle appelée Commentable et de faire en sorte que le belongs_to pointe vers cette classe de façon polymorphique. Voyons comment on peut le faire:

En console cela donne:

2.4.0 :001 > a = Article.new
 => #<Article id: nil, title: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil> 
2.4.0 :002 > c = Comment.new
 => #<Comment id: nil, content: nil, commentable_type: nil, commentable_id: nil, created_at: nil, updated_at: nil> 
2.4.0 :003 > c.commentable = a
 => #<Article id: nil, title: nil, content: nil, user_id: nil, created_at: nil, updated_at: nil> 
2.4.0 :004 > c.save
   (0.3ms)  begin transaction
  SQL (0.5ms)  INSERT INTO "articles" ("created_at", "updated_at") VALUES (?, ?)  [["created_at", "2017-07-14 18:08:49.067969"], ["updated_at", "2017-07-14 18:08:49.067969"]]
  SQL (0.2ms)  INSERT INTO "comments" ("commentable_type", "commentable_id", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["commentable_type", "Article"], ["commentable_id", 2], ["created_at", "2017-07-14 18:08:49.083467"], ["updated_at", "2017-07-14 18:08:49.083467"]]
   (361.3ms)  commit transaction
 => true 
2.4.0 :005 > a.reload.comments.count
  Article Load (0.6ms)  SELECT  "articles".* FROM "articles" WHERE "articles"."id" = ? LIMIT ?  [["id", 2], ["LIMIT", 1]]
   (0.2ms)  SELECT COUNT(*) FROM "comments" WHERE "comments"."commentable_id" = ? AND "comments"."commentable_type" = ?  [["commentable_id", 2], ["commentable_type", "Article"]]
 => 1