TL;DR: Ecto has this nice feature where you can Repo.update
a nested tree of changesets and Ecto figures out the appropriate SQL UPDATE and INSERT commands… or provides an error-annotated nested changeset.
I’ve been using that, and I keep encountering special cases. Am I doing something wrong? Do people use this feature or do they construct their own sequence of SQL commands?
Here’s the form in front of my recent code:
Submitting such a form requires (I think) a little massaging on the way into changeset-creation. Specifically, if the user didn’t attempt to fill in the “Add a gap” subform, that set of blank
values has to be removed from the HTTP parameters. (They wouldn’t pass validation and, even if they did, they certainly shouldn’t be given to INSERT.)
But removing an empty “gap” subform has implications when there are errors elsewhere:
- If there’s an error in only the top-level form (the animal), the animal’s changeset will have no entries for any gaps. So, having earlier removed the empty gap from the HTTP parameters, we have to make sure to create a new one for the “please fix these errors” version of the form.
- If the user tried to create a new gap with validation failures, the user should not be shown an empty form for creating a new gap. The previous attempt to do that should appear, with the appropriate error annotations.
- But if the validation failure was not in the “create a new gap” subform but rather in an update to one of the already-existing gaps,
Changeset.get_change(:gaps)
will have changesets for all of the existing gaps (the wrong one and all the others) - but we have to remember to provide the user with an empty form. (At least, that seems to me the most user-friendly course of action.)
The result is that I have code like this:
This level of special-case-ey-ness makes me think I must be doing something wrong.