I have a form that lets users set on and off time for a set of machines, this leads to the upsert of potentially several records (a ProductionDay
record is created for each machine that is toggled to on).
Because I have to update several records in a single form I decided to use an embedded_schema
to manage the user inputs then convert it back to ProductionDay
change sets before updating. I’ve seen and used this pattern before but on this particular form I’m having lots of issues I think because there is a mix of persisted data and data that is not perhaps.
When loading the form I get all Machines
and then create a %ProductionDay{}
record for them. If the machine is already set to on a ProductionDay
will exist in the database and be loaded, if it’s off I’ll need to create a ProductionDay
struct with some default data to pass to the form.
def create_changeset_for_location(%{id: id} = location, day) do
machines = Machines.all(location_id: id)
production_days = all(location_id: id, day: day)
production_days =
Enum.map(
machines,
fn %{id: id, name: name} ->
case Enum.find(production_days, &(&1.machine_id == id)) do
%ProductionDay{} = pd -> pd
_ -> %ProductionDay{ ...defaults...}
end
end
)
ProductionDayInput.changeset(%ProductionDayInput{production_days: production_days}, %{})
end
This creates a ProductionDayInput
changeset with embedded ProductionDays
:
defmodule App.ProductionDayUpdateInput do
embedded_schema do
embeds_many(:machine_days, ProductionDay)
end
def changeset(%ProductionDayUpdateInput{} = input, params \\ %{}) do
input
|> cast(params, [])
|> cast_embed(:machine_days)
end
end
Then when updating the LiveView I keep the change sets up to date like this:
%{assigns: %{production_day_changeset: prod_day}} = socket
ProductionDayUpdateInput.changeset(prod_day.data, params)
to update the changesets.
You may have already noticed the issue but with embeds_many
/cast_embed
I’m not actually associating the changes with the initial ProductionDay
records we embedded, it’s creating two new changesets because on_replace: update
is not an option. This means that when I go to persist this info I need to cherry pick between data
on the initial changesets and the changes
on the new ones. That feels clunky and like a hacky workaround.
I’ve tried first converting ProductionDay
to another embedded_schema
like ProductionDayPlaceholder
but I’ll always come up against the wall of trying to cast the changes using cast_embed
.
This question may seem similar to this one but I’m not necessarily looking for a way to force on_replace: update
I’m just trying to figure out the best way update/insert these ProductionDays
whatever it may be.