Adding id to assocs when inserting changeset

Hi, I have an Order model that has_many OrderItem.

I want to be able to insert an order and its order items with a single changeset:

alias MyApp.Orders.Order
alias MyApp.Orders.OrderItem

order = %{
  name: "Order 1",
  order_items: [
    %{
      sku_id: 1,
      quantity: 5
    },
    %{
      sku_id: 2,
      quantity: 10
    }
  ]
}

%Order{}
|> Order.changeset(order)
|> MyApp.Repo.insert!()

But Ecto points that order_items must have an order_id.

How can I generate the IDs properly?

Perhaps I am doing it wrong and should use a Multi?

What you have is normally fine, but it requires that your Order.changeset function has some stuff to make it work. Can you show what you have for that function?

Seconded! I’d check for a missing |> cast_assoc(:order_items).

Here’s an example from the Ecto Associations guide for reference:

Inserting parent and child records together

Using external data

# Params represent data from a form, API, CLI, etc
params = %{
  "title" => "Shawshank Redemption",
  "release_date" => "1994-10-14",
  "characters" =>
    [
      %{"name" => "Andy Dufresne", "age" => "50"},
      %{"name" => "Red", "age" => "60"}
    ]
}

%Movie{}
|> cast(params, [:title, :release_date])
|> cast_assoc(:characters)
|> Repo.insert()
1 Like

Check your OrderItem.changeset function - it shouldn’t have validate_required on order_id, but this result suggests that it does.

Thanks @benwilson512 and @al2o3cr

Removing validate_required from the changeset did it.

It also may be worth reviewing the assoc_constraint/3 and foreign_key_constraint/3 to see if that was what you actually want.

1 Like