Most clean way of insert multiple ids from a field of type list as associations

I’m using Absinthe to create graphql schemas, i have a graphql schema where one of types has a field of type array of UUIDs, eg:

type Car {
name: String!
color: String!
dealerships_ids: [UUID!]!
}

in my ecto schema dealerships_ids is a virtual field because it only exists on my graphql, it is not a column on my database, I have a table eg:
cars and dealerships_cars where I insert the car_id and dealership_id, finally my question is: there’s any clean or good way of insert all ids from my dealerships_ids on the pivot table after perform the car insert? like, get all ids during the insert and insert at the related table? the way I did is kinda verbose and spaghety like:

def create_car(attrs \\ %{}, opts = [prefix: prefix]) do
{:ok, car} =
 %Car{}
|> Cars.changeset(attrs)
|> Repo.insert(opts)

car.dealerships_ids
|> Enum.each(fn dealership_id ->
%Dealership{}
|>Dealerships.changeset(%{car_id: car.id, dealership_id: dealership_id})
|> Repo.insert(opts)
end)
end

I think this needs to be in a transaction though, what do you think?
This is done either with Ecto.Multi, Ecto.transaction, or nested changesets.

For example I generally achieve this with changesets like so:

%Car{}
|> Cars.changeset(attrs)
|> maybe_put_dealaerships(attrs)
|> Repo.insert(opts)
defp maybe_put_dealaerships(changeset, attrs) do
  dealerships_ids = attrs[:dealerships_ids] || attrs["dealerships_ids"]

  if dealerships_ids do
    dealerships = get_dealerships_by_ids(dealerships_ids)
    Ecto.Changeset.put_assoc(changeset, :dealerships, dealerships)
  else
    changeset
  end
end

I guess this runs an additional query (get_dealerships_by_ids) as opposed to your solution. However your code isn’t reusable for updates.

Note the use of attrs instead of a virtual field.

1 Like

i’m new to elixir, the line with |> maybe_put_dealaerships(attrs) will get the id of the inserted Car? to add at the related table?
because related table have the column car_id and dealership_id

I use the function Ecto.Changeset.put_assoc/4
I guess in your car schema you have an assoc field :dealerships

1 Like