Server-side params for AshPhoenix Form

Sometimes I will have an AshPhoenix form to create or update a resource, and I want some of the fields to be provided from the server and not set or visible on the client. Sometimes these are coming from uploads, other times it's computed from other state. What is the best way to provide this data to validate and submit? So far I've been defining a form_params(socket, params) helper that injects/overrides various params before passing the result to validate/submit. This has worked OK but feels wrong, and today I ran into an issue of having to reverse-engineer how AshPhoenix expects unions to work. Appreciate any insight and guidance y'all can provide!
8 Replies
barnabasj
barnabasj2mo ago
Have you tried using the params/prepare_params option for the for_* functions https://hexdocs.pm/ash_phoenix/AshPhoenix.Form.html#for_action/3
Fugi
FugiOP2mo ago
I don't think params would work as the values aren't known at the time mount is called (they are dependent on user actions/input). And prepare_params seems to only get the params as input, so it wouldn't be able to merge in outside data from the socket assigns?
barnabasj
barnabasj2mo ago
In that case, I think having a helper function like you did is totally valid or more like in general, not just this specific case
Fugi
FugiOP2mo ago
Appreciate it. I got worried because I felt I had to do some weird things when passing in union types to params and wondered if there was some other way to pass data in that made more sense. If there isn't then I'm happy to keep down this path!
barnabasj
barnabasj2mo ago
what exactly felt wierd about unions?
Fugi
FugiOP2mo ago
And I didn't see anything in the docs regarding this topic so didn't know if it was an expected way to go about it
barnabasj
barnabasj2mo ago
yeah, I think a lot of people think there is an Ash way for all of the things, but in the end it's all just functions anyway. Doesn't mean we can't make it more ergonomic if the need arises though.
Fugi
FugiOP2mo ago
One of my resources has a field of type {:array, :union} with storage: :map_with_tag and each type being a TypedStruct with tag: "type" and tag_value being some string. I expected to be able to pass in a list of maps with the type field set appropriately, but instead i had to convert them to a map of idx => %{"_union_type" => type, "value" => data} with a function kind of like this
def list_of_union_data_to_ash_param(l) do
Enum.with_index(l, fn value, idx -> {"#{idx}", %{"_union_type" => value["type"], "value" => value}} end)
|> Map.new()
end
def list_of_union_data_to_ash_param(l) do
Enum.with_index(l, fn value, idx -> {"#{idx}", %{"_union_type" => value["type"], "value" => value}} end)
|> Map.new()
end
I think this is because under the hood Ash is building a bunch of nested forms which expect this input. It wouldn't have been a problem if I was getting the union data from the client, but because I'm passing it in directly it went against Ash's expectations.

Did you find this page helpful?