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