Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix casting embedded schema with no fields and type on parent #114

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions lib/polymorphic_embed.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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? ->
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason this clause was removed?

Copy link
Author

@alisinabh alisinabh Dec 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this clause not removed, when there is an empty schema (an embedded schema with no fields), the casting will not work as this clause will stop the casting early.

You can try bringing this back and see the added test fail.

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)
Expand Down Expand Up @@ -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) ->
Expand Down
33 changes: 32 additions & 1 deletion test/polymorphic_embed_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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

Expand Down
14 changes: 14 additions & 0 deletions test/support/models/polymorphic/channel/broadcast.ex
Original file line number Diff line number Diff line change
@@ -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
2 changes: 2 additions & 0 deletions test/support/models/polymorphic/reminder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down Expand Up @@ -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,
Expand Down