diff --git a/lib/polymorphic_embed.ex b/lib/polymorphic_embed.ex index 7e64891..3f631f2 100644 --- a/lib/polymorphic_embed.ex +++ b/lib/polymorphic_embed.ex @@ -278,8 +278,12 @@ defmodule PolymorphicEmbed do module -> data_for_field = - Enum.find(list_data_for_field, fn datum -> - datum.id != nil and datum.id == params[:id] and datum.__struct__ == module + Enum.find(list_data_for_field, fn + %{id: id} = datum when not is_nil(id) -> + id == params[:id] and datum.__struct__ == module + + _ -> + nil end) embed_changeset = diff --git a/test/polymorphic_embed_test.exs b/test/polymorphic_embed_test.exs index d658271..f36bd60 100644 --- a/test/polymorphic_embed_test.exs +++ b/test/polymorphic_embed_test.exs @@ -1203,6 +1203,18 @@ defmodule PolymorphicEmbedTest do age: "aquarius", address: "address" } + ], + contexts3: [ + %{ + __type__: "device", + ref: "12345", + type: "cellphone" + }, + %{ + __type__: "device", + ref: "56789", + type: "laptop" + } ] } @@ -1212,7 +1224,11 @@ defmodule PolymorphicEmbedTest do |> Repo.insert!() Enum.each(reminder.contexts, fn context -> - assert context.id + assert Map.has_key?(context, :id) + end) + + Enum.each(reminder.contexts3, fn context -> + refute Map.has_key?(context, :id) end) reminder = @@ -1223,7 +1239,7 @@ defmodule PolymorphicEmbedTest do assert reminder.contexts |> length() == 2 Enum.each(reminder.contexts, fn context -> - assert context.id + assert Map.has_key?(context, :id) end) if polymorphic?(generator) do @@ -1286,6 +1302,27 @@ defmodule PolymorphicEmbedTest do assert Enum.at(reminder.contexts, 0).id == Enum.at(updated_reminder.contexts, 0).id assert Enum.at(reminder.contexts, 1).id != Enum.at(updated_reminder.contexts, 1).id + + # Make sure it also works for embeds without ids (`@primary_key false`) + attrs = %{ + contexts3: [ + %{ + __type__: "device", + ref: "12345", + type: "cellphone" + }, + %{ + __type__: "device", + ref: "56789", + type: "laptop" + } + ] + } + + assert {:ok, _} = + reminder + |> reminder_module.changeset(attrs) + |> Repo.update() end end diff --git a/test/support/migrations/20000101000000_create_tables.exs b/test/support/migrations/20000101000000_create_tables.exs index e1167f9..c43cda7 100644 --- a/test/support/migrations/20000101000000_create_tables.exs +++ b/test/support/migrations/20000101000000_create_tables.exs @@ -11,6 +11,7 @@ defmodule PolymorphicEmbed.CreateTables do add(:channel3, :map) add(:contexts, :map) add(:contexts2, :map) + add(:contexts3, :map) timestamps() end diff --git a/test/support/models/not_polymorphic/reminder.ex b/test/support/models/not_polymorphic/reminder.ex index cdbae77..03c596a 100644 --- a/test/support/models/not_polymorphic/reminder.ex +++ b/test/support/models/not_polymorphic/reminder.ex @@ -13,6 +13,10 @@ defmodule PolymorphicEmbed.Regular.Reminder do on_replace: :delete ) + embeds_many(:contexts3, PolymorphicEmbed.Regular.Reminder.Context.DeviceNoId, + on_replace: :delete + ) + timestamps() end @@ -22,6 +26,7 @@ defmodule PolymorphicEmbed.Regular.Reminder do |> validate_required(:date) |> cast_embed(:channel) |> cast_embed(:contexts) + |> cast_embed(:contexts3) end def custom_changeset(struct, attrs) do diff --git a/test/support/models/not_polymorphic/reminder/context/device_no_id.ex b/test/support/models/not_polymorphic/reminder/context/device_no_id.ex new file mode 100644 index 0000000..d863796 --- /dev/null +++ b/test/support/models/not_polymorphic/reminder/context/device_no_id.ex @@ -0,0 +1,21 @@ +defmodule PolymorphicEmbed.Regular.Reminder.Context.DeviceNoId do + use Ecto.Schema + import Ecto.Changeset + + @primary_key false + + embedded_schema do + field :ref, :string + field :type, :string + + embeds_one :extra, Extra do + field :imei, :string + end + end + + def changeset(struct, params) do + struct + |> cast(params, ~w(ref type)a) + |> validate_required(~w(type)a) + end +end diff --git a/test/support/models/polymorphic/reminder.ex b/test/support/models/polymorphic/reminder.ex index a77efb0..632a378 100644 --- a/test/support/models/polymorphic/reminder.ex +++ b/test/support/models/polymorphic/reminder.ex @@ -56,6 +56,15 @@ defmodule PolymorphicEmbed.Reminder do on_replace: :delete ) + polymorphic_embeds_many(:contexts3, + types: [ + location: PolymorphicEmbed.Reminder.Context.Location, + age: PolymorphicEmbed.Reminder.Context.Age, + device: PolymorphicEmbed.Reminder.Context.DeviceNoId + ], + on_replace: :delete + ) + timestamps() end @@ -66,6 +75,7 @@ defmodule PolymorphicEmbed.Reminder do |> cast_polymorphic_embed(:channel) |> cast_polymorphic_embed(:contexts) |> cast_polymorphic_embed(:contexts2) + |> cast_polymorphic_embed(:contexts3) end def custom_changeset(struct, values) do diff --git a/test/support/models/polymorphic/reminder/context/device_no_id.ex b/test/support/models/polymorphic/reminder/context/device_no_id.ex new file mode 100644 index 0000000..3f6f9a5 --- /dev/null +++ b/test/support/models/polymorphic/reminder/context/device_no_id.ex @@ -0,0 +1,21 @@ +defmodule PolymorphicEmbed.Reminder.Context.DeviceNoId do + use Ecto.Schema + import Ecto.Changeset + + @primary_key false + + embedded_schema do + field :ref, :string + field :type, :string + + embeds_one :extra, Extra do + field :imei, :string + end + end + + def changeset(struct, params) do + struct + |> cast(params, ~w(ref type)a) + |> validate_required(~w(type)a) + end +end