Path Helpers and form_for

I have run into an issue when using path helpers in a form_for function when trying to edit a resource. In this case I am trying to update an existing resource.

The router kicks out the following

categories_path  GET        /categories       MyApp.CategoriesController :index
categories_path  POST      /categories       MyApp.CategoriesController :create
categories_path  PATCH   /categories/:id   MyApp.CategoriesController :update
                            PUT       /categories/:id   MyApp.CategoriesController :update

My form_for opens as

<%= form_for(@client_changeset, categories_path(@conn, :update, @client), fn f -> %>

(the categories controller handles submissions for both clients and topics as they are the ‘categories’)

My understanding is, providing a changeset for an existing resource to form_for means the submission would be a POST to

/categories/<id of resource>

with

“_method” => “put” (or “patch”)?

I then take the params where I can use the id for fetching the resource from storage then sending that along with the client params for the update.

However. If I set up the form_for as shown I always get the error,

protocol Enumerable not implemented for %MyApp.Client{... etc }

If I remove the @client from the call to categories_path the error goes away, but the form submission does not include an id in the path.

Revised form_for

<%= form_for(@client_changeset, categories_path(@conn, :update), fn f -> %>

POSTs to

/categories

As a workaround I have added the id @client.id as a hidden field on the form so I can pluck it from the params. This however feels wrong and hacky, and doesn’t align with the boilerplate code a phoenix generator produces or my understanding of the path_helper included in the form_for action.

I’ve checked the categories_path in iex and I can pass

categories_path(MyApp.Endpoint, :update, Repo.get(Client, 1))

and it returns

"/categories/1"

as it should.

Any help here would be greatly appreciated. Thanks.

What error do you get if you try

<%= form_for(@client_changeset, categories_path(@conn, :update, @client, []), fn f -> %>

?

Can you show the code you use to generate the routes for categories?

I get

undefined function categories_path/4

router.ex for categories reads

resources("/categories", CategoriesController, only: [:index, :create, :update])

Just to be sure the parser isn’t irritated, have you tried form for without parentheses?

1 Like

It should be categories_path(@conn, :update, @client.id), it won’t extract the ID for you

1 Like

Since categories_path/4 doesn’t exist, the third argument in categories_path/3 is an option list, so I doubt categories_path(@conn, :update, @client.id) would work since @client.id is not a list of options.

And there is usually a Phoenix.Param implementation or something like that to, in this case, extract id out of @client, so if categories_path(@conn, :update, @client.id) worked, categories_path(@conn, :update, @client) would work as well.

1 Like

nevermind - now it works for me without id too, must be the gnomes

1 Like

Nobbz,

I appreciate you answering. Total face-palm moment.

The page has two forms on it, for the two categories. I was (like a complete fool) reading the error message which was about the second form while making changes to the first one!

Adding and removing parentheses finally woke me up to this as the stacktrace showed parens still in place. THAT’S WHEN I REALIZED. :frowning:

Sorry to have wasted everyone’s time


1 Like

See my note about me being a total fool, but, just FYI it works for me just using client, I don’t need to add the .id

Now I need to work on my stack trace reading skills.

1 Like

It’s either gnomes or robots you never know

2 Likes