How to manage belongs_to with phoenix form

michaelst57
2023-06-21

michaelst57:

Is there an example for how to manage belongs_to resource with phoenix form

michaelst57:

I can get it to populate existing data, but updates don’t work <.input id="agent" type="select" field={@form[:agent_id]} prompt="None" options={agent_ids(assigns)} />

zachdaniel:

🤔what does the action/form creation look like?

zachdaniel:

Not sure what examples are there for that specific case

michaelst57:

form = database |> AshPhoenix.Form.for_update(:update, api: QueryDesk.Api, forms: [auto?: true] ) |> to_form()

michaelst57:

it is just using the default update action

zachdaniel:

Does the action accept the agent id?

zachdaniel:

Or should you be using a nested form with :agent instead?

michaelst57:

oh something else I just realized, this could be a path for an IDOR attack, need to verify the id that is passed

michaelst57:

so I tried the nested form approach but nothing was showing up

zachdaniel:

Did you load the relationship on the record first?

michaelst57:

oh maybe no

zachdaniel:

Ash will validate reads against the related resource in order to associate them

zachdaniel:

So if the rule is just “can read the other thing” then you should be okay.

zachdaniel:

But policies for it may be necessary depending on your setup.

michaelst57:

ok so I should setup a policy to make sure the current user can read the agent and it will block the relationship to the database if not? need to make sure the records belong to the same account

michaelst57:

so auto?: true won’t setup the relationship forms, need to do it explicitly?

michaelst57:

<.inputs_for :let={agent_form} field={@form[:agent]}> <.input id="agent" type="select" field={agent_form[:id]} prompt="None" options={agent_ids(assigns)} />

michaelst57:

form = database |> AshPhoenix.Form.for_update(:update, api: QueryDesk.Api, forms: [ agent: [ type: :single, resource: QueryDesk.Resources.Agents.Agent ] ] ) |> to_form()

michaelst57:

still nothing showing up for the input

michaelst57:

oh maybe need data…

michaelst57:

so looks like that controls the value directly on the agent resource, instead of the agent_id of the database

zachdaniel:

Auto will set them up

zachdaniel:

But if there is no agent, it won’t add a form for it

zachdaniel:

So if you want that to happen automaticallly you’d need to check and use add_form if one isn’t present.

michaelst57:

with an agent connected I get this error when using auto agent at path [] must be configured in the form to be used with inputs_for . For example:

zachdaniel:

Do you have a manage_relationship on the action?

michaelst57:

oh no I don’t

zachdaniel:

Auto figures out the forms from manage_relationship calls

zachdaniel:

You can also just update agent_id but you need to set attribute_writable? true on the relationship to change agent_id

michaelst57:

oh let me try that route

michaelst57:

yes attribute_writable? worked! thank you so much!

michaelst57:

is there a reason manage_relationship would be better, is that where policies would be checked?

zachdaniel:

Yep!

michaelst57:

update :update do argument :agent, Agent change manage_relationship(:agent, type: :append_and_remove) end this doesn’t seem to be connecting to the form

zachdaniel:

With just setting the attribute, you’ll just want to make sure only the right ids are allowed.

zachdaniel:

You’ll need to change the way the form works to use the manage relationship type

zachdaniel:

Like switch it to use nested inputs

zachdaniel:

I.e inputs_for

michaelst57:

<.inputs_for :let={agent_form} field={@form[:agent]}> <.input id="agent" type="select" field={agent_form[:agent_id]} prompt="None" options={agent_ids(assigns)} />

michaelst57:

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

zachdaniel:

🤔

zachdaniel:

and you’re doing the forms: [auto?: true] still?

zachdaniel:

Definitely w/ the action that has the manage relationship still?

zachdaniel:

You can look at what AshPhoenix.Form.Auto.auto returns

michaelst57:

ya

michaelst57:

how would I do that?

michaelst57:

also once I get all these pieces put together I would like to submit a guide for setting this up, is there a good place to do that

zachdaniel:

Ash phoenix in a tutorial or topic would be great. There may be some guides there already too, or at least something that can point the way a bit better here

zachdaniel:

The thing I mentioned is a function you can call that will return the form config we generate

zachdaniel:

Take a look at the module I mentioned and there is a function there to return the config

michaelst57:

iex(1)> AshPhoenix.Form.Auto.auto(QueryDesk.Resources.Databases.Database, :update) []

zachdaniel:

Oh

zachdaniel:

argument :agent, :map

michaelst57:

Ah ok that got rid of the error, now to figure out what the field name is

michaelst57:

The select shows up but not populating the value

zachdaniel:

The field name is probably id

dblack1:

I might be missing something, but if the agent belongs_to the database resource, and all you’re trying to do is select the agent for the database (and not edit the agent resource within the database form), then you don’t need a nested form

dblack1:

the update action would look something like:

update :update do
  argument :agent_id, :uuid
  change manage_relationship(:agent_id, :agent, type: :append_and_remove)
end

and the form

<.input type="select" field={@form[:agent_id]} prompt="None" options={agent_ids(assigns)} />

michaelst57:

I will try that tonight, seems like that is the right approach

michaelst57:

That worked, thanks so much!