mathieuprog

mathieuprog

Hello :waving_hand:

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 :backhand_index_pointing_down:

https://github.com/mathieuprog/polymorphic_embed

Inspired by ecto_poly library.

Showing Posts 1 to 10

thomas.fortes

thomas.fortes

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 :slight_smile:

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.

mathieuprog

mathieuprog OP

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.

nwjlyons

nwjlyons

This looks really cool. I wonder if I could recreate Wagtail’s StreamField with this. Going to investigate…

mathieuprog

mathieuprog OP

polymorphic_embed is now using ParameterizedType! :clap:

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.

mathieuprog

mathieuprog OP

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.

mathieuprog

mathieuprog OP

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.
belaustegui

belaustegui

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.

mathieuprog

mathieuprog OP

  • Support for LiveView forms has been added thanks to the quality contribution of Mathias!

  • Support for primary keys has been added

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
mathieuprog

mathieuprog OP

Version 3.0.0 has been released!

We now encourage the use of polymorphic_embeds_one/2 and polymorphic_embeds_many/2 macros to define your polymorphic embeds.

If you’re curious as to why: a field containing a polymorphic list of embeds defaulted to nil before version 3. To follow embeds_many/3 we should default to []. This can only be done by forcing the :default option of the field/3 to [] (ie we can’t configure this in the Type). I added the new macros in order to set these kind of defaults setting up the field for the polymorphic embeds.

Thanks to Alexandre @Matsa59 for his contribution which led to this update!

mathieuprog

mathieuprog OP

A tricky bug has been fixed where atoms were not persisted in the compilation files. The atoms specifying the types were converted into strings in the Ecto Type’s init/1 function at compile-time, and so as we only worked with the strings afterwards, the atoms were not persisted:
https://github.com/mathieuprog/polymorphic_embed/issues/59

Fixed in 3.0.3 thanks to the support of @LostKobrakai on Slack and the contribution of Alessio ! :clap:

Where Next? Top

Trending in Announcing Top

achempion
Hi, I would like to tell about my initiative to further maintain and develop Waffle project which is the fork of Arc library. The progre...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
danschultzer
I’ve moved the strategies out of PowAssent and created a multi-provider framework for Elixir. This way the strategies can be used in any ...
New
gtcode
Aloha gang, There’s a new class of AI model out from TypeSafe. Jev is their flagship model. You can learn about it here: ...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
AstonJ
With advancements in AI gathering pace and set to increasingly accelerate, perhaps it’s worth having an annual thread on the topic - feel...
New
bartblast
If you haven’t tried Hologram yet, what’s stopped you? Here’s why I’m asking. Building a framework turns out to be two jobs, the framewo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews