Hello I already posted this question in the Elixir slack but I’m moving it here in the hopes of getting more eyes on it. A direct answer to my question or a link to an example would be much appreciated, thanks!
Im attempting to work with the PolymorphicEmbed library in a Phoenix 1.7.0-rc.0 app with LiveView 0.18.3. I want to make a form backed by changesets so that I benefit from easy validation. The issue that I am having is two-fold:
- When I start with a populated changeset like so
Poem.changeset(%Poem{}, %{stanzas: [%{content: "", __type__: "text"}]})
nil is the only clause that matches inPolymorphicEmbed.HTML.Form.get_polymorphic_type/3
- When I start with an empty changeset like so
Poem.changeset(%Poem{}, %{})
no fields render at all
How do I use the library to show form fields in a way that allows me to use Ecto changesets? I wish to show both empty forms when creating new poems AND populated forms when editing existing poems. If I need to manually cast form fields to the correct validators doesn’t that defeat the purpose of this library?
My schemas are:
defmodule Help.Poem do
use Ecto.Schema
import Ecto.Changeset
import PolymorphicEmbed
schema "poems" do
field :title, :string
polymorphic_embeds_many :stanzas,
types: [
text: [
module: __MODULE__.TextStanza,
identify_by_fields: [:content]],
image: [
module: __MODULE__.ImageStanza,
identify_by_fields: [:url]]],
on_type_not_found: :raise,
on_replace: :delete
timestamps()
end
def changeset(poem, attrs) do
poem
|> cast(attrs, [])
|> cast_polymorphic_embed(:stanzas,
with: [
text: &__MODULE__.TextStanza.changeset/2,
file: &__MODULE__.ImageStanza.changeset/2
])
|> validate_required([])
end
defmodule TextStanza do
use Ecto.Schema
embedded_schema do
field :content, :string
end
def changeset(text, attrs) do
text
|> cast(attrs, [:content])
|> validate_required(:content)
|> validate_length(:content, min: 5)
end
end
defmodule ImageStanza do
use Ecto.Schema
embedded_schema do
field :url, :string
end
def changeset(image, attrs) do
image
|> cast(attrs, [:url])
|> validate_required(:url)
end
end
end
My heex:
<.simple_form :let={poem_form} for={@poem_form} phx-change="validate-poem-form">
<%= for stanza_form <- polymorphic_embed_inputs_for poem_form, :stanzas do %>
<%= hidden_inputs_for(stanza_form) %>
<%= case get_polymorphic_type(stanza_form, Help.Poem, :stanzas) do %>
<% :text -> %>
<%!-- Never matches even with Poem.changeset(%Poem{}, %{stanzas: [%{content: "", __type__: "text"}]}) --%>
<% :image -> %>
<%!-- Never matches even with Poem.changeset(%Poem{}, %{stanzas: [%{url: "", __type__: "image"}]}) --%>
<% nil -> %>
<%!-- Always matches but how do I manually construct an input for an embeds_many field --%>
<% end %>
<% end %>
<:actions>
<.button>Post Poem</.button>
</:actions>
</.simple_form>