diff --git a/lib/ash_phoenix/form/auto.ex b/lib/ash_phoenix/form/auto.ex index f6ad0cf..7c7d4f9 100644 --- a/lib/ash_phoenix/form/auto.ex +++ b/lib/ash_phoenix/form/auto.ex @@ -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]} diff --git a/lib/ash_phoenix/form/form.ex b/lib/ash_phoenix/form/form.ex index b51e21f..209a7fb 100644 --- a/lib/ash_phoenix/form/form.ex +++ b/lib/ash_phoenix/form/form.ex @@ -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} diff --git a/test/auto_form_test.exs b/test/auto_form_test.exs index d5f6f58..e293370 100644 --- a/test/auto_form_test.exs +++ b/test/auto_form_test.exs @@ -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