danschultzer

danschultzer

Pow Core Team

Blog Post: Polymorphic embeds in Ecto

Recently I had to ensure semi-arbitrary data for an embedded schema could be validated and easily mapped in Phoenix forms. I didn’t need to store this data in the database. After tinkering with it for a bit polymorphic embeds was the solution.

Most Liked

tangui

tangui

Hi Dan,

Can’t thank you enough for this great write-up!

It became very useful as I was doing some funny things with [polymorphic_embed]( polymorphic_embed | Hex ), such as:

  • highlighting changed form fields by comparing field.form.data.<fieldname> with field.value
  • building a collaborative editing system relying on changesets (stored in DB)

image

In both case, this was impossible with polymorphic_embed because it defines a new Ecto type that does not fully behave like regular embeds (and cannot, because of limitations in Ecto), hence numerous bug reports on this library such as [this one]( Dan Schultzer: Polymorphic embeds in Ecto ).

But you cracked it with this trick:

    # We must modify the type so Ecto will handle this field as an embed.
    changeset = %{changeset | types: Map.put(changeset.types, name, {:embed, relation})}

Now, may I ask if you took a look at polymorphic_embed before writing this blog post, and if so why you didn’t use it in the first place?

I’m curious because, if as I suppose correctly and the author of polymorphic_embed didn’t know about le trick, then I guess it could be rewritten by deleting 80% of the code and eliminating 80% of the bugs :thinking:

Thinking out loud, but this library became unmaintained (it seems), is widely used and is riddled with subtle discrepancies compared with regular Ecto embeds. For those who would need it, a PR with “some” fixes here.

PS : might be a typo here:

    + {:parameterized, {__MODULE__, relation}} = Map.fetch!(types, name)
    - {:parameterized, __MODULE__, relation} = Map.fetch!(types, name)

Cheers!

danschultzer

danschultzer

Pow Core Team

I think the typo is actually from Ecto API change, I’m updating it thanks!

Yeah, I did look at the library but it doesn’t really solve polymorphic embeds with Ecto and neither does my small version here. The actual production version I have is more involved so it can handle some normalization, prepare changes, etc. But at the end of the day, embeds have some sharp corners and it only gets worse when you lose the guarantee with the struct which Ecto is built upon. There are a lot of assumptions with data structures in Ecto so I think the only way for polymorphic embeds to work properly is that Ecto needs to be changed in how embeds works. It’s been a while so I can’t remember the exact details, but if you go through the code path of how embeds are dumped/loaded you’ll see that embeds are treated separately from other data and it makes things tricky.

At least having all of this logic in your codebase you can adjust it for your exact needs and work around the sharp corners yourself. You often don’t need everything that the embed type need to be able to do.

Where Next?

Popular in Blog Posts Top

alexgaribay
I saw this thread so I decided to write about how we do it :smile:
New
ConnorRigby
Just finished a post for Embedded Elixir and I thought it should be cross-posted here: https://embedded-elixir.com/post/2018-09-25-mocks...
New
paulanthonywilson
Following up on the previous post on using UDP multicasting to broadcast and detect peers on a network, I create a registry of those peer...
New
mudasobwa
Just blogged on the general approach to creating easily extendable applications with plugin support.
New
axelson
I talk about how I really like to use runtime configuration and discuss some common pitfalls of configuration in Elixir.
New
ragamuf
Does the world need another How to create a blog article? Maybe not. But then again, creating something out of nothing is what we love....
New
brainlid
OTP 26 was released and the Elixir 1.14.4 builds have been updated! Erlang OTP 26 changed how map keys are sorted, or not sorted actually...
New
Paradox
Testing is an important part of any modern piece of software. But writing tests can quickly become an exercise in frustration, with tons ...
New
brainlid
In a 2 day spike, I created my own Elixir-based AI Personal Fitness Trainer! The surprising part for me was how useful and helpful I foun...
New
danschultzer
How to set up the Content Security Policy header with Phoenix LiveView and support inline styles and scripts with CSP nonces.
New

Other popular topics Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
AstonJ
Please see the new poll here: Which code editor or IDE do you use? (Poll) (2022 Edition) It’s been a while since we first asked this, I...
208 31265 143
New
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41989 114
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement