I'm having a hard time trying to achieve polymorphism in Ecto. My main problem is that i'm trying to handle polymorphic association in Phoenix, but with data coming from a database used and created by our - let's be honnest, a little old - main app, which is based on Rails.
Every other models are handled well and there's no problem to read or write data on both Rails and Phoenix's side.
Except for those with polymorphism. I spent a lot of time reading though Ecto's documentation and i get that the "rails way" is not the "right way" but i'm kind of stuck here, because my models are already written on the rails side (some of theme already store millions of rows).
So i have this abstract model element
, in Rails, which represents 7 tables (image, video, excel, etc..). And i have two other tables, doc_images
and items
. Those two other tables belongs_to element
and therefore have the rails magical fields element_id
and element_type
. Again, no element
table exists in postgres, only images
, videos
, etc.
I've tried to setup my images
and videos
models in Phoenix, but when i had this code into my items
schema :
schema "items" do
belongs_to(:video, Video, foreign_key: :element_id)
belongs_to(:image, Image, foreign_key: :element_id)
field(:element_type, :string)
timestamps([{:created_at, :updated_at}])
end
I can't compile because of (ArgumentError) field/association :element_id is already set on schema
.
I was okay with doing all queries by hand, but i can't seem to be able to write the schemas right.
In the end, i need to be able to make those kind of queries work (all of it is working perfectly fine except for the doc/video/image part, obviously) :
MyApp.Repo.one(from t in Token,
join: p in assoc(t, :project),
join: vc in assoc(p, :vcard),
join: th in assoc(p, :theme),
left_join: z in assoc(p, :zip_archive), on: p.id == z.project_id,
join: c in assoc(p, :company),
join: b in assoc(c, :binfos),
left_join: pi in assoc(p, :project_items), on: pi.id == pi.project_id,
left_join: i in assoc(pi, :item),
left_join: d in assoc(i, :doc),
left_join: v in assoc(i, :video),
left_join: im in assoc(i, :image),
left_join: di in assoc(d, :doc_image),
where: t.token_url == ^token_url,
preload: [project: [:vcard, :theme, :zip_archive, [company: :binfos], project_items: [item: [doc: :doc_image, :video, :image]]]])
So my question is : what other options do i have ? I can add columns and even other tables to my database (and migrate datas from the existing tables in it) but i can't remove the element
logic from my Rails app (mostly for time concern and because the other guys in my team love the Rails way :p).
Has anyone been able to handle polymorphism in Ecto the Rails way, event if it's strongly discouraged ?