Inputs_for does not include element id in hidden field

Hey, I’m using a inputs_for to render multiple fields, each with a input.

<.inputs_for :let={item} field={@form[:items]}>
  <td>
    <.input type="number" field={item[:quantity]} min={0} max={25} />
  </td>
</.inputs_for>

An item is a embeds_many on a parent schema:

    embeds_many :items, Item, on_replace: :delete do
      @derive Jason.Encoder
      field :name, :string
      field :image, :string
      field :variant_id, :string
      field :quantity, :integer
      field :price, :decimal
    end

Unfortunately, the hidden field generated by inputs_for is the following, which includes “_persistent_id” and not “id”:

<input type="hidden" name="draft_order_creation_form[items][0][_persistent_id]" value="0">

Which makes so that when I change values in the browser, the params submitted do not contain the element id, bu rather the _persistent_id

"items" => %{"0" => %{"_persistent_id" => "0", "quantity" => "1"}}

Because of that, Ecto can’t match on id, and thus can’t update the value when doing the cast_embed.

Am I missing something ?

Any help would be much appreciated!

inputs_for does include hidden fields: phoenix_live_view/lib/phoenix_component.ex at v0.20.17 · phoenixframework/phoenix_live_view · GitHub

If they are not showing up, it is either because the field is nil (or maybe the resource is not persisted), so there is no ID to go by. Here is the logic for getting fields from Ecto: phoenix_ecto/lib/phoenix_ecto/html.ex at main · phoenixframework/phoenix_ecto · GitHub

2 Likes

Hey @josevalim thanks for getting back to me!

Got it, the resource is in fact not persisted, but I am passing an ID value, this is the input to my to_form call.

#Ecto.Changeset<
  action: :validate,
  changes: %{
    items: [
      #Ecto.Changeset<
        action: :insert,
        changes: %{
          id: "some-unique-identifier",
          name: "some-name",
          image: "some-url",
          variant_id: "some-unique-identifier",
          quantity: 1,
          price: Decimal.new("2.99")
        },
        errors: [],
        data: #Pdex.DraftOrderCreationForm.Item<>,
        valid?: true
      >
    ]
  },
  errors: [],
  data: #Pdex.DraftOrderCreationForm<>,
  valid?: false
>

The schema for the parent and child items is the following (both are not persisted to the db)

defmodule Pdex.DraftOrderCreationForm do
  import Ecto.Changeset
  use Ecto.Schema

  @primary_key false
  embedded_schema do
    field :order_id, :string
    field :customer_id, :string
    embeds_many :items, Item, on_replace: :delete do
      @derive Jason.Encoder
      field :name, :string
      field :image, :string
      field :variant_id, :string
      field :quantity, :integer
      field :price, :decimal
    end
  end

Shouldn’t the fact that an id is present be enough to render it in the markup ? Or should the id be both present AND the resource a persisted one ?

Your embedded schemas do not have primary keys and the inputs_for needs to use the IDs of the association/embeds.

4 Likes

got it, ty @josevalim !