endymion

endymion

Why can't we have embeds_many :foo, :map where the embeds is a list of non-homogenous maps?

I have question on the limitations of embeds_many. I want non-homogenous embeds many.

Despite being able to define how to handle casting from the with option in embeds_many, casting fails when the type for the field is :map.

defmodule Container do
  use Ecto.Schema
  embedded_schema do
    embeds_many :foos_and_bars, :map
  end
end

defmodule Foo do
  use Ecto.Schema
  embedded_schema do
    field :position, :integer
    field :unique_data, :list
  end
end

defmodule Bar do
  use Ecto.Schema
  embedded_schema do
    field :position, :integer
    field :more_unique_data, :bool
  end

The issue arises when I need to call cast_embed on the Container to validate foos_and_bars

container = %Container{foos_and_bars: [%Bar{position: 1, more_unique_data: true}]}
params = %{
  foos_and_bars: %{
    "1" => %{more_unique_data: false}
}}

Ecto.Changeset.cast(container, params, [])
|> Ecto.Changeset.cast_embed(:foos_and_bars, with: fn foo_or_bar, params ->
  case foo_or_bar do
    foo = %Foo{} -> Foo.changeset(foo, params)
    bar = %Bar{} -> Foo.changeset(bar, params)
  end
end)

The cast_embed throws (UndefinedFunctionError) function :map.__schema__/1 is undefined (module :map is not available) :map.__schema__(:primary_key) as it expects the field to be a schema not just a plain :map.

My question is why is this the case? I understand that there may not be an obvious use for field backed by a database to need this type flexiblity but when changesets are the first class supported method of input validation in Phoenix these issues arrive. The wider context is for my application we have an ordered list of inputs. Some those “inputs” are nested input lists. To maintain the order correctly inside of the inputs_for we need to store an Enumerable with two types (a plain input or nested group of inputs). Problems arrise when casting the changeset as described above.

I can further understand why this error could get thrown if Ecto.Changeset.cast_embed was not called alongside the with option. The with allows you to define how to handle casting for each item in the embeds. which in my opinion should allow me to have case that matches on type and delegates to those modules changeset functions.

embeds_many :foos_and_bars, :map should either raise an exception or the case should be handled as described above.

Marked As Solved

al2o3cr

al2o3cr

This sounds like exactly what polymorphic_embed was designed to do:

Without the “type” field that that uses, it’s not possible to figure out which schema the results should be when retrieving a schema that says embeds_many

If you really care exclusively about writing these shapes, consider saying field :foos_and_bars, :map and then manually using Foo and Bar’s changesets to produce maps in cast_embed.

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
jerry
Good day to you all. I have been struggling to get a query involving like and ilike to work. Can anyone assist me on this, please? pro...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
idi527
I’ve been re-reading swift book again and noticed that multiline strings there don’t have a trailing line break, unlike in elixir iex(2)...
New

Other popular topics Top

rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
977 41022 311
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: https://hexdocs.pm/ecto/Ecto.Schema.html#module-...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New

We're in Beta

About us Mission Statement