How to manage belongs_to with phoenix form

Is there an example for how to manage belongs_to resource with phoenix form
28 Replies
michaelst
michaelstOP•2y ago
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)} />
<.input id="agent" type="select" field={@form[:agent_id]} prompt="None" options={agent_ids(assigns)} />
ZachDaniel
ZachDaniel•2y ago
🤔what does the action/form creation look like? Not sure what examples are there for that specific case
michaelst
michaelstOP•2y ago
form =
database
|> AshPhoenix.Form.for_update(:update,
api: QueryDesk.Api,
forms: [auto?: true]
)
|> to_form()
form =
database
|> AshPhoenix.Form.for_update(:update,
api: QueryDesk.Api,
forms: [auto?: true]
)
|> to_form()
it is just using the default update action
ZachDaniel
ZachDaniel•2y ago
Does the action accept the agent id? Or should you be using a nested form with :agent instead?
michaelst
michaelstOP•2y ago
oh something else I just realized, this could be a path for an IDOR attack, need to verify the id that is passed so I tried the nested form approach but nothing was showing up
ZachDaniel
ZachDaniel•2y ago
Did you load the relationship on the record first?
michaelst
michaelstOP•2y ago
oh maybe no
ZachDaniel
ZachDaniel•2y ago
Ash will validate reads against the related resource in order to associate them So if the rule is just “can read the other thing” then you should be okay. But policies for it may be necessary depending on your setup.
michaelst
michaelstOP•2y ago
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 so auto?: true won't setup the relationship forms, need to do it explicitly?
<.inputs_for :let={agent_form} field={@form[:agent]}>
<.input id="agent" type="select" field={agent_form[:id]} prompt="None" options={agent_ids(assigns)} />
</.inputs_for>
<.inputs_for :let={agent_form} field={@form[:agent]}>
<.input id="agent" type="select" field={agent_form[:id]} prompt="None" options={agent_ids(assigns)} />
</.inputs_for>
form =
database
|> AshPhoenix.Form.for_update(:update,
api: QueryDesk.Api,
forms: [
agent: [
type: :single,
resource: QueryDesk.Resources.Agents.Agent
]
]
)
|> to_form()
form =
database
|> AshPhoenix.Form.for_update(:update,
api: QueryDesk.Api,
forms: [
agent: [
type: :single,
resource: QueryDesk.Resources.Agents.Agent
]
]
)
|> to_form()
still nothing showing up for the input oh maybe need data... so looks like that controls the value directly on the agent resource, instead of the agent_id of the database
ZachDaniel
ZachDaniel•2y ago
Auto will set them up But if there is no agent, it won’t add a form for it So if you want that to happen automaticallly you’d need to check and use add_form if one isn’t present.
michaelst
michaelstOP•2y ago
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
ZachDaniel•2y ago
Do you have a manage_relationship on the action?
michaelst
michaelstOP•2y ago
oh no I don't
ZachDaniel
ZachDaniel•2y ago
Auto figures out the forms from manage_relationship calls You can also just update agent_id but you need to set attribute_writable? true on the relationship to change agent_id
michaelst
michaelstOP•2y ago
oh let me try that route yes attribute_writable? worked! thank you so much! is there a reason manage_relationship would be better, is that where policies would be checked?
ZachDaniel
ZachDaniel•2y ago
Yep!
michaelst
michaelstOP•2y ago
update :update do
argument :agent, Agent
change manage_relationship(:agent, type: :append_and_remove)
end
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
ZachDaniel•2y ago
With just setting the attribute, you’ll just want to make sure only the right ids are allowed. You’ll need to change the way the form works to use the manage relationship type Like switch it to use nested inputs I.e inputs_for
michaelst
michaelstOP•2y ago
<.inputs_for :let={agent_form} field={@form[:agent]}>
<.input id="agent" type="select" field={agent_form[:agent_id]} prompt="None" options={agent_ids(assigns)} />
</.inputs_for>
<.inputs_for :let={agent_form} field={@form[:agent]}>
<.input id="agent" type="select" field={agent_form[:agent_id]} prompt="None" options={agent_ids(assigns)} />
</.inputs_for>
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•2y ago
🤔 and you're doing the forms: [auto?: true] still? Definitely w/ the action that has the manage relationship still? You can look at what AshPhoenix.Form.Auto.auto returns
michaelst
michaelstOP•2y ago
ya how would I do that? 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
ZachDaniel•2y ago
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 The thing I mentioned is a function you can call that will return the form config we generate Take a look at the module I mentioned and there is a function there to return the config
michaelst
michaelstOP•2y ago
iex(1)> AshPhoenix.Form.Auto.auto(QueryDesk.Resources.Databases.Database, :update)
[]
iex(1)> AshPhoenix.Form.Auto.auto(QueryDesk.Resources.Databases.Database, :update)
[]
ZachDaniel
ZachDaniel•2y ago
Oh argument :agent, :map
michaelst
michaelstOP•2y ago
Ah ok that got rid of the error, now to figure out what the field name is The select shows up but not populating the value
ZachDaniel
ZachDaniel•2y ago
The field name is probably id
dblack
dblack•2y ago
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 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
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)} />
<.input type="select" field={@form[:agent_id]} prompt="None" options={agent_ids(assigns)} />
michaelst
michaelstOP•2y ago
I will try that tonight, seems like that is the right approach That worked, thanks so much!

Did you find this page helpful?