diff --git a/lib/polymorphic_embed.ex b/lib/polymorphic_embed.ex index 85387f4..8a266f9 100644 --- a/lib/polymorphic_embed.ex +++ b/lib/polymorphic_embed.ex @@ -185,9 +185,6 @@ defmodule PolymorphicEmbed do {:ok, nil} when not required -> Ecto.Changeset.put_change(changeset, field, nil) - {:ok, map} when map == %{} and not array? -> - changeset - {:ok, params_for_field} when array? -> create_sort_default = fn -> sort_create(Enum.into(cast_opts, %{}), field_opts) end params_for_field = apply_sort_drop(params_for_field, sort, drop, create_sort_default) @@ -365,10 +362,15 @@ defmodule PolymorphicEmbed do is_nil(type_from_map) -> module = get_polymorphic_module_for_type(type_from_parent_field, types_metadata) - if is_nil(data_for_field) or data_for_field.__struct__ != module do - {:insert, struct(module)} - else - {:update, data_for_field} + cond do + is_nil(module) -> + :type_not_found + + is_nil(data_for_field) or data_for_field.__struct__ != module -> + {:insert, struct(module)} + + true -> + {:update, data_for_field} end to_string(type_from_parent_field) != to_string(type_from_map) -> diff --git a/test/polymorphic_embed_test.exs b/test/polymorphic_embed_test.exs index 7dced00..2b8a39b 100644 --- a/test/polymorphic_embed_test.exs +++ b/test/polymorphic_embed_test.exs @@ -1133,6 +1133,37 @@ defmodule PolymorphicEmbedTest do end end + test "cast embed with a schema that has no fields" do + broadcast_reminder_attrs = %{ + date: ~U[2020-05-28 02:57:19Z], + text: "This is a Broadcast reminder polymorphic", + channel: %{ + my_type_field: "broadcast" + } + } + + changeset = + PolymorphicEmbed.Reminder.changeset(%PolymorphicEmbed.Reminder{}, broadcast_reminder_attrs) + + assert changeset.valid? + assert changeset.changes.channel == %PolymorphicEmbed.Channel.Broadcast{} + end + + test "cast embed with a schema that has not fields and type is in parent" do + broadcast_reminder_attrs = %{ + date: ~U[2020-05-28 02:57:19Z], + text: "This is a Broadcast reminder polymorphic", + type: "broadcast", + channel4: %{} + } + + changeset = + PolymorphicEmbed.Reminder.changeset(%PolymorphicEmbed.Reminder{}, broadcast_reminder_attrs) + + assert changeset.valid? + assert changeset.changes.channel4 == %PolymorphicEmbed.Channel.Broadcast{} + end + test "cast embed after change/2 call should succeed" do for generator <- @generators do reminder_module = get_module(Reminder, generator) @@ -3452,7 +3483,7 @@ defmodule PolymorphicEmbedTest do describe "types/2" do test "returns the types for a polymoprhic embed field" do assert PolymorphicEmbed.types(PolymorphicEmbed.Reminder, :channel) == - [:sms, :email] + [:sms, :broadcast, :email] end end diff --git a/test/support/models/polymorphic/channel/broadcast.ex b/test/support/models/polymorphic/channel/broadcast.ex new file mode 100644 index 0000000..980635a --- /dev/null +++ b/test/support/models/polymorphic/channel/broadcast.ex @@ -0,0 +1,14 @@ +defmodule PolymorphicEmbed.Channel.Broadcast do + use Ecto.Schema + import Ecto.Changeset + + @primary_key false + + embedded_schema do + # A schema with no fields + end + + def changeset(broadcast, params) do + cast(broadcast, params, ~w()a) + end +end diff --git a/test/support/models/polymorphic/reminder.ex b/test/support/models/polymorphic/reminder.ex index 73e42e8..c77da29 100644 --- a/test/support/models/polymorphic/reminder.ex +++ b/test/support/models/polymorphic/reminder.ex @@ -15,6 +15,7 @@ defmodule PolymorphicEmbed.Reminder do polymorphic_embeds_one(:channel, types: [ sms: PolymorphicEmbed.Channel.SMS, + broadcast: PolymorphicEmbed.Channel.Broadcast, email: [ module: PolymorphicEmbed.Channel.Email, identify_by_fields: [:address, :confirmed] @@ -45,6 +46,7 @@ defmodule PolymorphicEmbed.Reminder do polymorphic_embeds_one(:channel4, types: [ sms: PolymorphicEmbed.Channel.SMS, + broadcast: PolymorphicEmbed.Channel.Broadcast, email: PolymorphicEmbed.Channel.Email ], on_replace: :update,