Nested embedded Resource Form

I have an embedded resource which contains multiple other embedded resources. When I use AshPhoenix.Form.for_update with forms: [auto?: true], the form created does not contain information about any of the embedded resources other than the first key. Right now I am adding the missing data like so
update_form =
AshPhoenix.Form.for_update(styles, :update,
api: Timshel.Ash.Api,
forms: [auto?: true]
)
|> AshPhoenix.Form.add_form(:background, type: :update, data: styles.background)
|> AshPhoenix.Form.add_form(:text, type: :update, data: styles.text)
|> AshPhoenix.Form.add_form(:border, type: :update, data: styles.border)
|> AshPhoenix.Form.add_form(:size, type: :update, data: styles.size)
update_form =
AshPhoenix.Form.for_update(styles, :update,
api: Timshel.Ash.Api,
forms: [auto?: true]
)
|> AshPhoenix.Form.add_form(:background, type: :update, data: styles.background)
|> AshPhoenix.Form.add_form(:text, type: :update, data: styles.text)
|> AshPhoenix.Form.add_form(:border, type: :update, data: styles.border)
|> AshPhoenix.Form.add_form(:size, type: :update, data: styles.size)
Is there something I have to set up in the update action of the root level embedded resource? Additionally, when adding the form in assigns after validation, the diff sent over the wire is huge. Any tips on reducing the payload for large forms? Splitting up something in some way?
12 Replies
ZachDaniel
ZachDaniel•3y ago
🤔 interesting You shouldn't need to, I wonder if we aren't traversing embeds to find nested embeds? As for the diff, I think perhaps some new phoenix stuff will help with that, combined with component-izing the form i.e
<.background_form form={form}/>
<.text_form form={form}/>
<.border_form form={form}/>
<.background_form form={form}/>
<.text_form form={form}/>
<.border_form form={form}/>
The new phoenix stuff has you track the html form itself via to_form() after creating the form Could you show me what AshPhoenix.Form.Auto.embedded(Resource, action, []) gives you? It comes with an updater function (because these can be recursive, it must be lazily evaluated), so you may need to then do something like:
opts = AshPhoenix.Form.Auto.embedded(Resource, action, [])

forms =
opts
|> Keyword.get(:forms)
|> Enum.map(fn {key, config} ->
if config[:updater] do
{key, config[:updater].(config)}
else
{key, config}
end
end)

opts = Keyword.put(opts, :forms, forms)
opts = AshPhoenix.Form.Auto.embedded(Resource, action, [])

forms =
opts
|> Keyword.get(:forms)
|> Enum.map(fn {key, config} ->
if config[:updater] do
{key, config[:updater].(config)}
else
{key, config}
end
end)

opts = Keyword.put(opts, :forms, forms)
That should show us what each embed has
gvanders
gvandersOP•3y ago
Took out the Keyword.get(:forms before the map
gvanders
gvandersOP•3y ago
Since that looks right, just checked something. In the actual data, I had one of the embedded resources set to nil (the second one). When it's not nil it appears. Sorry for that. I don't know if Ash should handle that case, but I'll make sure theres default empty structs I'm parsing a tailwind string into resources, and then converting it back to string after form is submitted. So I just need to make sure theres an empty resource
ZachDaniel
ZachDaniel•3y ago
Yeah, you could potentially do something like add_form ... for each thing you want to ensure an empty form exists for
gvanders
gvandersOP•3y ago
Mmm yeah probably simplest if I just keep the add_form
ZachDaniel
ZachDaniel•3y ago
For updates though I think that could potentially clobber the existing form at that path We could probably add something like add_new_form(:path, ...)
gvanders
gvandersOP•3y ago
Then I'd have to know ahead of time which are nil. Which I guess is easy. If I have the data option set, I assume it shouldn't matter if the form is clobbered?
|> AshPhoenix.Form.add_form(:background, type: :update, data: styles.background)
|> AshPhoenix.Form.add_form(:background, type: :update, data: styles.background)
Is this something I'd implement on my side? Or that we'd add to AshPhoenix?
ZachDaniel
ZachDaniel•3y ago
I think we'd probably add that to AshPhoenix potentially just as an option to add_form add_form(..., replace?: false)
gvanders
gvandersOP•3y ago
ahhh sorry that question was to a comment earlier in the thread
ZachDaniel
ZachDaniel•3y ago
oh, okay I see That is something that you'd implement on your side AshPhoenix has been updated for all of its functions to handle being given an AshPhoenix.Form or a Phoenix.HTML.Form So it really just depends on how much interaction you do with the ash form but in later versions of phoenix you can just call to_form() on your ash form before assigning it
gvanders
gvandersOP•3y ago
I'll take a look! Thanks for all the help 🙂
ZachDaniel
ZachDaniel•3y ago
My pleasure 🙂

Did you find this page helpful?