brady131313
How to create AshPhoenix form with Union field
I’m trying to create a form which has a list of nested items, each of which contain some union field. I have the following hierarchy: WorkoutTemplate has many SetGroupTemplate where SetGroupTemplate looks like the following module and both FixedReps and ClassicOverload are embedded ash resources
defmodule Weightroom.Template.SetGroupTemplate do
@moduledoc false
use Ash.Resource,
domain: Weightroom.Template,
data_layer: AshPostgres.DataLayer
alias Weightroom.Template.Progression
attributes do
uuid_primary_key :id
attribute :order, :integer, public?: true, allow_nil?: false
attribute :progression, :union do
public? true
allow_nil? false
constraints types: [
fixed_reps: [
type: Progression.FixedReps,
tag: :type,
tag_value: :fixed_reps
],
classic_overload: [
type: Progression.ClassicOverload,
tag: :type,
tag_value: :classic_overload
]
]
end
end
relationships do
belongs_to :workout, Weightroom.Template.WorkoutTemplate do
allow_nil? false
end
belongs_to :exercise, Weightroom.Journal.Exercise do
allow_nil? false
public? true
end
end
postgres do
table "set_group_templates"
repo Weightroom.Repo
references do
reference :workout, on_delete: :delete
reference :exercise, on_delete: :delete
end
custom_statements do
statement :unique_order do
up ~s|ALTER TABLE set_group_templates ADD CONSTRAINT set_group_templates_unique_order_index UNIQUE (workout_id, "order") DEFERRABLE INITIALLY DEFERRED|
down "ALTER TABLE set_group_templates DROP CONSTRAINT set_group_templates_unique_order_index"
end
end
end
actions do
defaults [:read, :destroy, create: :*]
end
When I create the form and try to add a new SetGroupTemplate I get the following error
template
|> AshPhoenix.Form.for_update(:update, forms: [auto?: true])
|> AshPhoenix.Form.add_form("form[set_groups]",
params: %{
"progression" => %{
"_union_type" => "fixed_reps"
}
}
)
** (RuntimeError) Got no "_union_type" parameter, and no union type had a tag & tag_value pair matching the params.
If you are adding a form, select a type using `params: %{"_union_type" => "type_name"}`, or if one
or more of your types is using a tag you can set that tag with `params: %{"tag" => "tag_value"}`.
Params:
%{}
Available types:
[
classic_overload: [
type: Weightroom.Template.Progression.ClassicOverload,
constraints: [on_update: :update_on_match],
tag: :type,
tag_value: :classic_overload
],
fixed_reps: [
type: Weightroom.Template.Progression.FixedReps,
constraints: [on_update: :update_on_match],
tag: :type,
tag_value: :fixed_reps
]
]
If I instead use “type” instead of “_union_type” as the key for the new progression I get the same error. Stepping through the code of ash authentication it looks like AshPhoenix.Form.Auto.determine_type/3 is called twice. The first time with the map of params and it doesn’t raise. The second time, params is empty and the function raises.
I saw there is a test for union forms here and I can’t see what I’m doing differently other than using an embedded resource for the union type instead of a simple type like string/int/etc. Any help understanding where I’m going wrong would be appreciated.
Marked As Solved
Neophen
Ok figured it out,
the
defmodule Octafest.Pages.Block do
use Ash.Type.NewType,
subtype_of: :union,
constraints: [
types: [
hero_simple: [
type: HeroSimple,
tag: :type,
tag_value: :hero_simple
],
hero_media: [
type: HeroMedia,
tag: :type,
tag_value: :hero_media
]
]
]
end
has to be in a single file by itself
Same for all the others subtypes
Also Liked
Neophen
brady131313
@zachdaniel using main of ash_phoenix works as expected. I can pass the type of the union using both :_union_type and :tag and it works, thank you.
Neophen
Works beautifully:
def handle_event("add_block", %{"type" => type}, socket) do
form =
socket.assigns.form
|> AshPhoenix.Form.add_form("form[blocks]", params: get_params(type))
{:noreply, assign(socket, :form, form)}
end
defp get_params("hero_media" = type), do: %{
"_union_type" => type,
"image" => %{
"url" => "",
"alt" => "",
"image_id" => "",
"modifiers" => %{}
}
}
defp get_params("hero_simple" = type), do: %{ "_union_type" => type }
defp get_params(type), do: %{ "_union_type" => type }
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








