Added on edit, 2013-02-11:
I should make it clearer that the problem I'm having is not that I can't get the ERB code I write to produce correct HTML code. Rather, it is that my Rails installation sometimes interprets the HTML code correctly, so that clicking the link has the right effect, and sometimes incorrectly, producing a "No route" error. More details in my answer below.
Original question, 2013-02-08:
I'm making a simple login form using Rails 3.2.11. I've tried several ways of coding the Submit button of the form, but each has failed due to a missing route error. I got one method to work, and checked in my code. However, now the very same code fails.
This is the code of app/views/session/new.html.erb
(I'm using simple_form
, but not its button wrapper):
<h2>Log in</h2>
<%= simple_form_for :session do |f| %>
<%= f.input :username %>
<%= f.input :password %>
<%= button_to "Submit", session_index_path %>
<% end %>
The relevant part of the HTML code that this produces is:
<h2>Log in</h2>
<form accept-charset="UTF-8" action="/session/new" class="simple_form session" method="post" novalidate="novalidate">
<div style="margin:0;padding:0;display:inline">...</div>
...the input fields...
<form action="/session" class="button_to" method="post">
<div>
<input type="submit" value="Submit" />
<input name="authenticity_token" type="hidden" value="...token value here..." />
</div>
</form>
</form>
This is my config/routes.rb
:
MyApp::Application.routes.draw do
resources :at_user
resources :session, :only => [:new, :create, :destroy]
match 'login' => 'session#new', as: :login
match 'logout' => 'session#destroy', as: :logout
root to: 'main#index'
end
This is what the command rake routes
outputs:
at_user_index GET /at_user(.:format) at_user#index
POST /at_user(.:format) at_user#create
new_at_user GET /at_user/new(.:format) at_user#new
edit_at_user GET /at_user/:id/edit(.:format) at_user#edit
at_user GET /at_user/:id(.:format) at_user#show
PUT /at_user/:id(.:format) at_user#update
DELETE /at_user/:id(.:format) at_user#destroy
session_index POST /session(.:format) session#create
new_session GET /session/new(.:format) session#new
session DELETE /session/:id(.:format) session#destroy
login /login(.:format) session#new
logout /logout(.:format) session#destroy
root / main#index
The target path of button_to
is session_index_path
, which should cause the create
method of SessionController
to be called -- and for a while, it did. Now, after I've restarted Rails, pressing the button instead produces an error page, with the text
No route matches [POST] "/session/new"
For some reason, Rails has started to think that the target of button_to
is session#new
instead of session#create
. It's as if it thinks that the HTTP method it's supposed to call is GET instead of POST -- however, the HTML code shows that the method is post.
By the way, another thing I earlier tried was to give button_to
the action and method parameters, as documented here:
<%= button_to "Submit", options: {action: 'create', method: :post} %>
then this is what's generated:
<form action="/session/new?options%5Baction%5D=create&options%5Bmethod%5D=post" class="button_to" method="post">
which doesn't look like what I want, either. button_to
's default HTTP method is POST, which appears in the result, but the :options
hash is just tacked onto the end of the URL, and the word create
appears nowhere else.
The first answer to this question says that, unlike what the documentation says, one should not put the parameters of button_to
in a hash, but give them directly. So, I tried this:
<%= button_to "Submit", action: 'create' %>
However, the action create
still does not show up in the generated HTML:
<form action="/session" class="button_to" method="post">
So, those were things I tried before attempting to using the named path method, which worked for a minute, but for some mysterious reason, doesn't anymore.
Any ideas what I'm doing wrong? (It's probably something obvious I've overlooked.)
The problem was most probably that after I created the application, I decided to change the names of a couple of the classes and the associated files. This resulted in class and file names that didn't follow the Rails convention on pluralizing nouns in certain contexts. For instance, I had a file session_controller.rb
that contained a class named SessionController
; the correct names are sessions_controller.rb
and SessionsController
.
I created a dummy Rails application, and then commanded rails generate scaffold AtUser
and rails generate scaffold Session
, and then used the resulting filenames and identifiers as a guide for correcting the actual application. Now, I don't get those "No route" errors anymore. The command rake routes
outputs:
at_users GET /at_users(.:format) at_users#index
POST /at_users(.:format) at_users#create
new_at_user GET /at_users/new(.:format) at_users#new
edit_at_user GET /at_users/:id/edit(.:format) at_users#edit
at_user GET /at_users/:id(.:format) at_users#show
PUT /at_users/:id(.:format) at_users#update
DELETE /at_users/:id(.:format) at_users#destroy
sessions POST /sessions(.:format) sessions#create
new_session GET /sessions/new(.:format) sessions#new
session DELETE /sessions/:id(.:format) sessions#destroy
login /login(.:format) sessions#new
logout /logout(.:format) sessions#destroy
root / main#index
Before this, I saw a "No route" error also when I included a file in another file without having require
d the former at the top of the latter. After performing the renaming fix, I tried to reproduce this error, and it did reoccur: Rails mistakenly reports a missing route, when the actual problem is a missing require
statement. This suggests that Rails's error reporting mechanism is buggy.
Thanks to user bullfrog for pointing me in the right direction.