How to get the parent assoc in polymorphic associations in ecto?

Hi everybody,

I’m following the guide on Polymorphic Associations and they talk about 3 options to do that in ecto.

An example of polymorphic association is a Comment that can belongs_to different kind of objects (or schema) like to a Post or a Task, taking the same example as the docs…

Here I’ll talk about the Post or Task being the parent objects (in which there will be the has_one/has_many) and the Comment being the child object (having the belongs_to).

In my case, I’m on a situation where a Comment can only have (so can only belongs_to) one parent, either a Task or a Post. And a Post or a Task will only have (has_one) child as a Comment.

The way Rails does it, using two additional fields e.g. commentable_type and commentable_id is not advised and they present 3 options in ecto:

  1. Having dedicated reference id fields in the Comment table for each associated parent, so here it will be task_id and post_id

  2. Using an abstract table, with an common assoc_id field.

  3. Using many_to_many through dedicated intermediary association tables.

The problem with the guides is that there are only partial code examples and I’m not sure how to deal with the related associations for each of these case.
Mainly, how I can reference and get the parent a Comment belongs to?

For example, for the case 1, I guess that the Comment schema could be like this:

schema "comments" do
  ... comment fields
  belongs_to :post, Post
  belongs_to :task, Task
end

But here I guess I’m not able anymore to use a foreign key constraint and use on_delete since I can have null on either one of these references.
Also, what I wanted is to refer to either Post or Task as a Parent for example comment.parent.
Is it possible for this case 1 ?

For the case 2, where there are now two table for the Comments, post_comments and task_comments. In the guide it’s clear how to handle the association from the parents (has_many :comments, {"posts_comments", Comment}, foreign_key: :assoc_id) but I have no clue how to do it on the Comment side.
And I also don’t have any idea about if I can then access to a parent as a generic one.

Regarding the third example, it also lacks of details on the Comment side, and I’m not sure how to get a parent.

To bring more perspective, in my case, the Comment is more like a Status which I can access as a notification/token. And from here I wanted to automatically grab and display the associated Task or Post.

Thank you for any advise…

Foreign key constraints can work with null columns, we use this pattern all the time.

1 Like

In the meantime I tested the 3rd option (using many_to_many).
While it’s working well, because it’s a many-to-many relationships, I’m always getting a List when I read the child value (after using preload).
And because I have only one child element that can belongs_to the parent, it’s really annoying to dealing with Lists.
What could be the best solution for getting rid of the List and always having the first element returned?

Foreign key constraints can work with null columns, we use this pattern all the time.

I think I will try that first solution which also seems the most simple. I also found how I can set a check constraint and ensure that there is only one of the foreign key set to null at any given time.

But I also want to try the option 2 using the abstract table.

I found this excellent SO question (despite being quite old) where the expert talk about 3 solutions:

  • Exclusive Arcs
  • Reverse the Relationship
  • Concrete Supertable

If I understood correctly these are the exact same 3 options listed on the Ecto doc, right?
And then what is referred as a concrete supertable seems that it will be an abstract table here in ecto…

Does anybody already used abstract table?