Cast_assoc and put_assoc/4 not correctly linking the belongs_to id when creating on the fly?

I’m trying to create a List and a list of associated ListGame records at the same time.

def changeset(list, attrs) do
  list
  |> cast(attrs, [:title, :description, :user_id, :is_ranked, :is_private])
  |> cast_assoc(:list_games, with: &ListGame.changeset/2)
end

My form data is coming in from my liveview as this, and it’s what I send to my create_list/1 function :

%{
  "description" => "Some description",
  "is_private" => "false",
  "is_ranked" => "true",
  "list_games" => %{
    "0" => %{
      "description" => "Some description",
      "game_id" => "1be81fb0-0cc9-4eb7-82d7-05265e2cf25c",
      "position" => "1"
    },
    "1" => %{
      "description" => "Some description",
      "game_id" => "a6aa2e85-d664-4d63-a372-1ea13e5d97bb",
      "position" => "2"
    },
    "2" => %{
      "description" => "Some description",
      "game_id" => "fb5cdbc6-6237-4627-b1fa-4fadd14be117",
      "position" => "3"
    }
  },
  "search_term" => "sekiro",
  "title" => "Test List",
  "user_id" => "0edb2303-68ce-47ec-aa82-f8dcf2f4a02f"
}

# This is being sent into:
%List{}
|> List.changeset(attrs)
|> Repo.insert()

However the changeset comes back with these errors:

#Ecto.Changeset<
  action: :insert,
  changes: %{
    description: "Some description",
    is_private: false,
    is_ranked: true,
    list_games: [
      #Ecto.Changeset<
        action: :insert,
        changes: %{
          description: "Some description",
          game_id: "1be81fb0-0cc9-4eb7-82d7-05265e2cf25c",
          position: 1
        },
        errors: [list_id: {"can't be blank", [validation: :required]}],
        data: #MyApp.Lists.ListGame<>,
        valid?: false
      >,
      #Ecto.Changeset<
        action: :insert,
        changes: %{
          description: "Some description",
          game_id: "a6aa2e85-d664-4d63-a372-1ea13e5d97bb",
          position: 2
        },
        errors: [list_id: {"can't be blank", [validation: :required]}],
        data: #MyApp.Lists.ListGame<>,
        valid?: false
      >,
      #Ecto.Changeset<
        action: :insert,
        changes: %{
          description: "Some description",
          game_id: "fb5cdbc6-6237-4627-b1fa-4fadd14be117",
          position: 3
        },
        errors: [list_id: {"can't be blank", [validation: :required]}],
        data: #MyApp.Lists.ListGame<>,
        valid?: false
      >
    ],
    title: "Test List",
    user_id: "0edb2303-68ce-47ec-aa82-f8dcf2f4a02f"
  },
  errors: [],
  data: #MyApp.Lists.List<>,
  valid?: false
>

Am I giving the attrs in the wrong shape for Ecto to automatically link the list_games to the list as it’s being created?

I’m creating both the List and the ListGame in the same form.

The id is set on insert not when casting. So your validation simply runs too early or rather it cannot run after the id will be set. Just remove the validation, as the id is not set by user input anyways.

1 Like

My man…

image

Four days of tears and sweat solved by this itty bitty thing. You ROCK!