fix: properly fill union values on update

This commit is contained in:
Zach Daniel 2024-06-07 15:59:29 -04:00
parent e333471888
commit 15afafee09
3 changed files with 143 additions and 80 deletions

View file

@ -152,68 +152,72 @@ defmodule AshPhoenix.Form.Auto do
updater =
fn opts, data, params ->
{type_name, type, constraints, tag, tag_value} =
determine_type(constraints, data, params)
if is_nil(data) and is_nil(params) do
opts
else
{type_name, type, constraints, tag, tag_value} =
determine_type(constraints, data, params)
{embed, constraints, fake_embedded?} =
if Ash.Type.embedded_type?(type) do
{type, constraints, false}
else
{AshPhoenix.Form.WrappedValue, [], true}
end
{embed, constraints, fake_embedded?} =
if Ash.Type.embedded_type?(type) do
{type, constraints, false}
else
{AshPhoenix.Form.WrappedValue, [], true}
end
prepare_source =
if fake_embedded? do
fn source ->
case source do
%Ash.Changeset{} ->
Ash.Changeset.set_context(source, %{type: type, constraints: constraints})
prepare_source =
if fake_embedded? do
fn source ->
case source do
%Ash.Changeset{} ->
Ash.Changeset.set_context(source, %{type: type, constraints: constraints})
%Ash.Query{} ->
Ash.Query.set_context(source, %{type: type, constraints: constraints})
%Ash.Query{} ->
Ash.Query.set_context(source, %{type: type, constraints: constraints})
end
end
end
end
transform_params =
if fake_embedded? do
union_param_transformer(type_name)
else
fn _form, params, _type ->
set_tag_value(params, tag, tag_value)
transform_params =
if fake_embedded? do
union_param_transformer(type_name)
else
fn _form, params, _type ->
set_tag_value(params, tag, tag_value)
end
end
end
create_action =
if constraints[:create_action] do
Ash.Resource.Info.action(embed, constraints[:create_action])
else
Ash.Resource.Info.primary_action(embed, :create)
end
create_action =
if constraints[:create_action] do
Ash.Resource.Info.action(embed, constraints[:create_action])
else
Ash.Resource.Info.primary_action(embed, :create)
end
update_action =
if constraints[:update_action] do
Ash.Resource.Info.action(embed, constraints[:update_action])
else
Ash.Resource.Info.primary_action(embed, :update)
end
update_action =
if constraints[:update_action] do
Ash.Resource.Info.action(embed, constraints[:update_action])
else
Ash.Resource.Info.primary_action(embed, :update)
end
Keyword.merge(opts,
resource: embed,
create_action: create_action.name,
update_action: update_action.name,
prepare_source: prepare_source,
transform_params: transform_params,
embed?: true,
save_updates?: false,
forms:
Keyword.new(
embedded(embed, create_action, auto_opts) ++
embedded(embed, update_action, auto_opts) ++
unions(embed, create_action, auto_opts) ++
unions(embed, update_action, auto_opts)
)
)
Keyword.merge(opts,
resource: embed,
create_action: create_action.name,
update_action: update_action.name,
prepare_source: prepare_source,
transform_params: transform_params,
embed?: true,
save_updates?: false,
forms:
Keyword.new(
embedded(embed, create_action, auto_opts) ++
embedded(embed, update_action, auto_opts) ++
unions(embed, create_action, auto_opts) ++
unions(embed, update_action, auto_opts)
)
)
end
end
{attr.name,
@ -269,6 +273,14 @@ defmodule AshPhoenix.Form.Auto do
determine_type(constraints, nil, params)
end
defp determine_type(
constraints,
%AshPhoenix.Form.WrappedValue{value: %Ash.Union{} = union},
params
) do
determine_type(constraints, union, params)
end
defp determine_type(constraints, nil, params) when params == %{} do
{key, config} = Enum.at(constraints[:types], 0)
{key, config[:type], config[:constraints], config[:tag], config[:tag_value]}

View file

@ -370,11 +370,24 @@ defmodule AshPhoenix.Form do
@doc "Calls the corresponding `for_*` function depending on the action type"
def for_action(resource_or_data, action, opts \\ [])
def for_action(%Ash.Union{value: value, type: type}, action, opts) do
def for_action(%Ash.Union{value: value, type: type} = union, action, opts) do
opts =
Keyword.put_new(opts, :transform_params, AshPhoenix.Form.Auto.union_param_transformer(type))
form = for_action(value, action, opts)
data =
case value do
%struct{} = value ->
if Ash.Resource.Info.resource?(struct) do
value
else
%AshPhoenix.Form.WrappedValue{value: union}
end
_value ->
%AshPhoenix.Form.WrappedValue{value: union}
end
form = for_action(data, action, opts)
%{form | params: Map.put(form.params, "_union_type", to_string(type))}
end
@ -4431,30 +4444,67 @@ defmodule AshPhoenix.Form do
end
true ->
if data && data != [] do
if opts[:update_action] || opts[:read_action] do
handle_form_without_params(
forms,
params,
opts,
key,
domain,
actor,
tenant,
trail,
prev_data_trail,
error?,
name,
id,
transform_errors,
warn_on_unhandled_errors?
)
else
cond do
!data ->
{forms, params}
end
else
{forms, params}
opts[:type] == :list ->
form_values =
data
|> List.wrap()
|> Enum.with_index()
|> Enum.map(fn {data, index} ->
opts = update_opts(opts, data, nil)
if opts[:update_action] do
for_action(data, opts[:update_action],
domain: domain,
actor: actor,
tenant: tenant,
errors: error?,
params: add_index(params, index, opts),
accessing_from: opts[:managed_relationship],
prepare_source: opts[:prepare_source],
updater: opts[:updater],
warn_on_unhandled_errors?: warn_on_unhandled_errors?,
prev_data_trail: prev_data_trail,
forms: opts[:forms] || [],
transform_params: opts[:transform_params],
transform_errors: transform_errors,
as: name <> "[#{key}][#{index}]",
id: id <> "_#{key}_#{index}"
)
end
end)
{Map.put(forms, key, Enum.filter(form_values, & &1)), params}
true ->
opts = update_opts(opts, data, nil)
form_value =
if opts[:update_action] do
for_action(data, opts[:update_action],
domain: domain,
actor: actor,
tenant: tenant,
errors: error?,
accessing_from: opts[:managed_relationship],
prepare_source: opts[:prepare_source],
warn_on_unhandled_errors?: warn_on_unhandled_errors?,
transform_params: opts[:transform_params],
updater: opts[:updater],
prev_data_trail: prev_data_trail,
forms: opts[:forms] || [],
transform_errors: transform_errors,
as: name <> "[#{key}]",
id: id <> "_#{key}"
)
end
{Map.put(forms, key, form_value), params}
end
end
else
{forms, params}

View file

@ -346,11 +346,12 @@ defmodule AshPhoenix.AutoFormTest do
"text" => "foobar"
}
)
|> Phoenix.HTML.FormData.to_form([])
# |> Phoenix.HTML.FormData.to_form([])
# IO.inspect(Phoenix.Component.inputs_for(%{field: form[:union], __changed__: %{}}))
# assert "update" == AshPhoenix.Form.value(form[:union], :value)
assert Enum.at(form[:union].value, 0)[:value].value == %Ash.Union{
value: :update,
type: :predefined
}
end
end