egor

egor

I’m building an application with a plugin system where each component can have different configuration parameters based on the plugin type selected.

I’ve implemented the Union Forms approach from the documentation for my plugin parameters, but I’m encountering an issue.

My Setup

I have a resource (Plugin) with a params attribute that uses a union type to accommodate different plugin parameter structures:

defmodule MyApp.Plugins.Plugin do
  use Ash.Resource, otp_app: :my_app, domain: MyApp.Plugins, data_layer: AshPostgres.DataLayer

  # Other configuration...

  attributes do
    integer_primary_key :id
    attribute :name, :string
    attribute :active, :boolean, default: false
    attribute :plugin_type, :module
    # This is the union attribute that holds different parameter configurations
    attribute :params, :plugin_params
    # Other attributes...
  end

  # Actions, relationships, etc.
end

The union type for plugin parameters:

defmodule MyApp.Types.PluginParams do
  defmodule TypeAParams do
    use Ash.Resource, data_layer: :embedded

    attributes do
      attribute :window_size, :integer, default: 3000
      attribute :threshold, :float, default: 0.70
      # Other parameters...
    end

    actions do
      defaults [:read, :destroy, create: :*, update: :*]
    end
  end

  use Ash.Type.NewType,
    subtype_of: :union,
    constraints: [
      types: [
        type_a: [
          type: TypeAParams,
          tag: :type,
          tag_value: :type_a
        ]
        # Other plugin types...
      ]
    ]
end

In my form component:

<.inputs_for :let={fc} field={@form[:params]}>
  <.input
    field={fc[:_union_type]}
    phx-change="type-changed"
    type="select"
    label="Plugin Type"
    options={["Type A": "type_a"]}
  />

  <%= case fc.params["_union_type"] do %>
    <% "type_a" -> %>
      <.input type="number" label="Window Size" field={fc[:window_size]} />
      <% # Other type_a inputs... %>
  <% end %>
</.inputs_for>

The Issue

When rendering the form, the current values are correctly displayed in the inputs. However, when I try to change any input in the nested form, I get this error:

%Ash.Error.Invalid.NoSuchInput{
  calculation: nil,
  resource: MyApp.Types.PluginParams.TypeAParams,
  action: :update,
  input: "window_size",
  inputs: MapSet.new([]),
  did_you_mean: [],
  # Other error details...
}

I’m following the type-changed handler from the documentation:

def handle_event("type-changed", %{"_target" => path} = params, socket) do
  new_type = get_in(params, path)
  path = :lists.droplast(path)

  form =
    socket.assigns.form
    |> AshPhoenix.Form.remove_form(path)
    |> AshPhoenix.Form.add_form(path, params: %{"_union_type" => new_type})

  {:noreply, assign(socket, :form, form)}
end

Any insights on what I might be doing wrong? The form renders correctly with the initial values but fails when trying to update any field.

Showing Posts 1 to 2

zachdaniel

zachdaniel

Creator of Ash

Something definitely seems strange there. The new_type definitely lines up with one of the union type names? The adding and removing paths are correct? If it ends up being a bug I’ll probably need a reproduction to pin it down as the union form rendering is a bit complex internally.

egor

egor OP

I figured out the issue. Turns out the bug wasn’t in Ash itself, but in the docs! The examples for union forms were missing public? true on the embedded resource attributes, which caused the updates to fail. I’m gonna submit a PR (#324) to fix that.

To reproduce the problem I’ve created a repo minibikini/ash_phoenix_union_form_example which now has a working example of a union form in Ash, perhaps someone will find it useful.

— All posts loaded —

Where Next? Top

Trending in Questions Top

stjefim
Hello! Suppose you are building workflow (order / task / payment) processing system with the following requirements: Each workflow con...
New
water
I’m aware of 2 such projects, are there others? git: GitHub - team-alembic/realworld: A fullstack Phoenix LiveView application with back...
New
katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New

Other Trending Topics Top

KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews