Obromios
Obromios

Reputation: 16393

Why does form_for helper require index path for a new action

I have the following in my routes file

resources :details, only: [:show, :edit, :update, :new]

and in new.html.erb

<%= form_for(@detail) do |f| %>
  <%= render 'fields', f: f %>
<% end -%>

and in the details controller

  def new
    @detail = Detail.new
  end

When the new.html.erb is rendered, I get the following error message

undefined method `details_path' for #<#<Class:0x007fc4ac6bd730>:0x007fc4b62e7390>

What is causing this?

Upvotes: 0

Views: 678

Answers (3)

Richard Peck
Richard Peck

Reputation: 76784

To give context to your answer, you need to look up about the resourceful nature of Rails' routes:

Browsers request pages from Rails by making a request for a URL using a specific HTTP method, such as GET, POST, PATCH, PUT and DELETE. Each method is a request to perform an operation on the resource. A resource route maps a number of related requests to actions in a single controller.

When you say... "form_for helper is looking to post to /details", it's actually looking to post your form data to the create method. The way it does this is through the POST verb on the /details route:

enter image description here

Thus, you need to ensure that you're declaring your create route if you wish to use the resourceful routing structure.

This is why you'll need the following:

#config/routes.rb
resources :details, only: [:show, :edit, :update, :new, :create]
or
resources :details, except: :index

--

Of course, you don't have to use it.

You can use whichever routes you want. The important thing, though, is to understand that Rails is built around convention; HTTP's is towards resources:

The server, which provides resources such as HTML files and other content, or performs other functions on behalf of the client, returns a response message to the client

This is why you have "resourceful" routing etc.

On top of Rails' object orientated nature, you need to appreciate which resources are being used at certain points in your app.

form_for expects a new object to route to the create route. You can override this by using the url: option:

<%= form_for @object, url: none_resourceful_path ...

Upvotes: 1

Tom Prats
Tom Prats

Reputation: 7921

The create and index actions use the same path but different actions. So if you have either in the routes file, then a details_path method will be generated. In your case you want to make sure you have the create in your routes file:

resources :details, only: [:create, :show, :edit, :update, :new]

Upvotes: 1

Obromios
Obromios

Reputation: 16393

The cause of this is that the the form_for helper is looking to post to /details. So it is not looking for the index path but the :create path.

So you need to add the :create action to your routes declaration

resources :details, only: [:show, :edit, :update, :new, :create]

If you look at the rendered html in this case, it will look like this

<form class="new_detail" id="new_detail" action="/details" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" />

so you can see why you need the :create path which makes the post /details path.

Upvotes: 4

Related Questions