I have a problem that does not seem to have a straightforward solution to me, but it feels like it should have one:
How should we go about saving a form (adding/removing/updating entries) that produces a list of changesets, makes the operations in the DB and then refreshes the form with the new values?
I know that is possible when the form is based on a schema that has an embeds_many or has_many, as we have a guide in LiveView docs and also the excellent One-to-Many LiveView Form | Benjamin Milde article from @lostkobrakai, but given I would like to change multiples entries that doesn’t belongs_to a unique schema, how can I put this together inside a single form?
This question comes from a page that I’m trying to build that should allow the user to add a new entry in the DB, update an existing one or delete it, like in a bulk operation. Also, the table should have constraints, and therefore I thought using changesets would make it easy to handle and return error messages for inputs.
I’ve put a gist that goes into the direction of what I want, but I’m stuck in saving the list of changesets and refreshing the form based on this list:
How would you tackle that? Would you simply not use form to solve this problem?
I believe I’m trying this approach with the MailingList embedded schema here. The thing is that I want to insert/update/delete only the changeset list of emails. Given I can grab it with get_embed(mailing_list, :emails), I tried iterating over the list of emails and applying them to the DB, but I could not figure out how to apply them back in the MailingList changeset.
Is having a MailingList embedded schema what you had in mind?
Yes, I have. I think the form wasn’t behaving correctly when I tried it because I was calling put_embed after the changesets being applied to the DB, which caused them to have the action replace and it left the form in a wrong state.
I guess I found a workaround for that, which is to reinitialise the original changeset instead of trying to update it after applying the operations to the DB. The code is something like this now:
def save(changeset) do
emails_changesets = get_embed(changeset, :emails)
case apply_changesets(emails_changesets) do
{:ok, emails_list} -> {:ok, MailingList.changeset(%MailingList{emails: emails_list})}
{:error, emails_changesets} -> {:error, put_embed(changeset, :emails, emails_changesets)}
end
end