Hello 
I published a library that brings support for polymorphic/dynamic embeds in Ecto.
Ecto’s embeds_one
macro requires a specific schema module to be specified. This library removes this restriction by dynamically determining which schema to use, based on data to be stored (from a form or API) and retrieved (from the data source).
Example use case:
Say you have a Reminder schema. A reminder has a set date and text, but also specific fields whether it is an email reminder or sms reminder. Instead of adding and mixing all the email- and sms-related fields together in the Reminder schema, where one set of fields or the other are null values, you can add a polymorphic embed, only containing the relevant sms or email fields. The polymorphic embed also supports its own changeset validations.
See example code and usage in Readme file 
Inspired by ecto_poly library.
13 Likes
Awesome, I’ve been working exactly with this problem this past week, my solution was built with an Ecto custom type, it works perfectly, but there’s a lot of boilerplate…
From the docs it seems like it will be almost a plug and play with just some minor adjustments, will open a branch and try it 
Edit: Yeah, looking at the source of the lib it does what I was doing manually with a custom type, it took zero modifications in the code aside of changing the field type in the schema and configuring the lib, so far all the tests passed.
2 Likes
I imagine this is a pretty common need, and that many codebases would either have a schema with sets of null values, or end up having their own custom Ecto type implementations.
This library indeed provides a custom Ecto Type that determines the right embed schema to use, based on params to cast. Nice thing is, you can tell PolymorphicEmbed
that the presence of specific params identifies a certain schema – no need for a “type” field in the params:)
In addition to the advantages that a library offers (get rid of boilerplate code in the app, reusable code across projects, bugfixes, …), it comes with some nice features:
- As mentioned, detect which types to use for the data being
cast
-ed, based on fields present in the data (no need for a type field in the data)
- Run changeset validations when a
changeset/2
function is present (when absent, the library will introspect the fields to cast)
- Support for nested polymorphic embeds
- Support for nested
embeds_one
/embeds_many
embeds
- Display form inputs for polymorphic embeds in Phoenix templates
Added those features in the Readme file.
3 Likes
This looks really cool. I wonder if I could recreate Wagtail’s StreamField with this. Going to investigate…
polymorphic_embed
is now using ParameterizedType
! 
Polymorphic embeds are now specified as parameters on the field:
schema "reminders" do
field :channel, PolymorphicEmbed,
types: [
sms: MyApp.Channel.SMS,
email: MyApp.Channel.Email
]
No more intermediary module for options, code injection and macros.
Note also that for those using it, an (unrelated) bugfix requires now casting params for polymorphic embeds through cast_polymorphic_embed/2
instead of cast/4
.
See example in readme.
1 Like
Support for lists of polymorphic embeds has been added! Thanks to the great contribution of @jmnsf.
Code has also been drastically simplified and improved thanks to brilliant contributions from @maennchen.
The :on_replace
option has been added and must be set to :update
for single polymorphic embeds and :delete
for lists of polymorphic embeds. These are the only supported modes when replacing records. We force to specify the option as omitting this option for embeds_one
/embeds_many
defaults its value to :raise
.
1 Like
Support for ecto_sqlite3
has been added in version 1.7.0!
Other features added:
-
:with
option allowing to specify a custom changeset;
-
:required
option to specify whether the embed is required or not;
-
traverse_errors/2
function to include polymorphic embeds’ errors.
3 Likes
Just wanted to jump in and say thanks for this awesome library @mathieuprog
We have been using it for the last few months at my day job and it has been an absolute pleasure. Works well and reliably and the documentation is top-notch.
3 Likes
The latter may introduce breaking changes, therefore Polymoprhic Embed version has been bumped to 2.0.0
Migration from 1.x to 2.x is easy:
- Make sure that every existing polymorphic
embedded_schema
contains the setting @primary_key false
6 Likes