andreh

andreh

Hi! First, I’d like to say that AshPhoenix.Form is really great, it makes dealing with forms so much easier! To implement an e-invoicing pipeline, I’m playing with Reactor and would like to know if it is possible to use it together with AshPhoenix.Form.

The main issue I’m facing is that my Invoice resource handles many items through manage_relationship and I don’t know how to pass that to the Reactor.

Here’s my Invoice resource:

defmodule Sales.Invoice do
  actions do
    defaults [:read]

    create :issue do
      primary? true

      accept [
        :discount_tax_rate,
        :discount_type,
        :discount_value,
        :issue_date,
        :payment_mean,
        :payment_terms_days,
        :payment_terms_days_end_of_month,
        :status,
        :contact_id
      ]

      argument :items, {:array, :map}, allow_nil?: false
      change manage_relationship(:items, type: :direct_control, order_is_key: :number)

      # many more validations and change
    end

    action :complete_issue, :struct do
     # Do I have to repeat alls arguments here?
     # And what about change manage_relationship(:items, type: :direct_control, order_is_key: :number)?
 
      run Reactors.IssueInvoice
    end
  end
end

And here’s the Reactor:

defmodule Reactors.IssueInvoice do
  use Ash.Reactor

  # Do I have to repeat all the inputs here?
  input :discount_tax_rate
  input :discount_type
  input :discount_value
  input :issue_date
  input :payment_mean
  input :payment_terms_days
  input :payment_terms_days_end_of_month
  input :status
  input :contact_id
  input :items

  step :check_access_point, Sales.Invoice.Steps.CheckAccessPoint do
    max_retries 3
  end

  transaction :create_invoice_transaction, [Sales.Invoice, Audit.AuditLog] do
    wait_for :check_access_point

    # Do I have to repeat all the inputs here?
    create :create_invoice, Sales.Invoice, :issue do
      inputs %{
        discount_tax_rate: input(:discount_tax_rate),
        discount_type: input(:discount_type),
        discount_value: input(:discount_value),
        issue_date: input(:issue_date),
        payment_mean: input(:payment_mean),
        payment_terms_days: input(:payment_terms_days),
        payment_terms_days_end_of_month: input(:payment_terms_days_end_of_month),
        status: input(:status),
        contact_id: input(:contact_id),
        items: input(:items)
      }
    end
    
     # Other steps...
    return :create_invoice
  end

  return :create_invoice_transaction
end

And of course, this is the error I get:

[error] ** (AshPhoenix.Form.NoFormConfigured) items at path [] must be configured in the form to be used with `inputs_for`. For example:

There is an argument called `items` on the action `Sales.Invoice.complete_issue`.

Perhaps you are missing a `change manage_relationship` for that argument, or it is not a type that can have forms generated for it?

So I guess the question is: it is possible to benefit from all the goodness of Ash.Changeset and Ash.Phoenix.Form while using Ash.Reactor?

I’ve managed to get a working solution using hooks, but it would be nice to benefit from the compensation and retry/backoff features of Reactor.

Hope I’m clear enough, let me know!

Most Liked

ken-kost

ken-kost

Assuming you’re auto deriving the form; it doesn’t work in this case because it’s going through a generic action which has no manage_relationship that could be picked up. Hence the error, and the solution is to manually configure the nested forms, i.e. manually initialize the form and be explicit in what you want:

AshPhoenix.Form.for_action(Sales.Invoice, :complete_issue,  
  forms: [  
    items: [  
      type: :list,  
      resource: Sales.InvoiceItem,  
      create_action: :create 
    ]  
  ]  
)

More on this here.

When AshPhoenix.Form.params/1 is called on submit, it collects all nested item params and assembles them under the "items" key, which gets passed as the items argument to complete_issue — and from there into your Reactor.

Where Next? Top

Trending in Questions Top

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
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
ChrisAmelia
I’ve got trouble wrapping my head around the order in which functions are called in this snippet (from Phoenix’s authentication): toke...
New
dillonoconnor
Is there any way to avoid the Hologram compiler running when using iex? It seems like the front-end code could potentially be disregarded...
New
thiagogsr
** (ArgumentError) expected :max_attempts to be a positive integer, got: {:@, [line: 10, column: 19], [{:max_attempts, [line: 10, column:...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
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
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews