Rails routing to the wrong URL
I wrote a form within views of a non-user model, allowing visitors to login. I want开发者_如何学C to first check out if this is working. So I make the action "index" to take a test.
<%form_tag(:controller=>"users",:action=>"index") do %>
Name: <%=text_field_tag "name" %><br>
Password: <%=password_field_tag "password" %><br>
<%=submit_tag "Login" %>
<% end -%>
Surprisingly, rails routing directs the page to the "new" view while the browser navigation bar still displays:
http://0.0.0.0:3000/users
When I refresh the page, it displays the normal "index" page.
Why is this happening?
What is even more eerie, when I changed the :action
in code above to :action=>"new"
, the screen displays "routing error". When I refresh it, it presents the normal "new" view.
the users_controller.rb
is as follows:
class UsersController < ApplicationController
def index
@users=User.all
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => @users }
end
end
def show
@user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => @user }
end
end
def login
flash[:notice]="Hello";
end
def new
end
def create
@user = User.new(params[:project])
respond_to do |format|
if @user.save
format.html { redirect_to(@user, :notice => 'user was successfully created.') }
format.xml { render :xml => @user, :status => :created, :location => @user }
else
format.html { render :action => "new" }
format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
end
end
end
end
My routes.rb goes as follows:
Testdrive::Application.routes.draw do
resources :users do
member do
post 'login'
end
end
resources :cars
Apneadiving's answer is correct, however I think it's important to clarify some things:
What page are you trying to get the user to? It sounds like you want the user to get to the index page (you're surprised that the user is landing on the new page).
First: you should understand the relationship between the type of HTTP request you make and the place the controller directs the browser to. See http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions
Basically your form is submitting a POST request, to the /users
url. The Controller always routes POSTS to this address to your CREATE action. Thus, as Apneadiving explained, the post params you're sending are not the ones that CREATE is expecting, so save fails and you're redirected to users/new
Now, I see that in your form you specified: :controller => 'users', :action => 'index'
. So, this is where I see it looks like you want people to land on the index page. What you need to understand, however, is that the Rails form helpers are not magically linked to the controller layer.
Second: Know that information flow is basically one-way in Rails: things from the model can go to the controller, but not the other way. Things from the controller can go to the view, but not the other way.
The only thing that the controller can receive from the user is an HTTP request. When you use the form tag helpers you're just using a shortcut for defining the action
and method
attributes of an HTML form
element. See http://www.w3.org/TR/html401/interact/forms.html#h-17.13
So, even though you specified :action => 'index'
, your form is still sending a POST request (forms POST by default). The controller doesn't know that you meant for the person's request to hit the index action, it only knows that it received a POST, not a GET, at the /users
url. Therefore it routes that request to the CREATE action.
That's what REST is all about.
The solution:
You need to use an action that isn't already predefined. In your routes it looks like you tried to do this when you put:
resources :users do
member do
post 'login'
end
end
This code would correctly accept POST requests to users/123/login
.
However, because you specified this on a MEMBER of the user's collection rather than on the COLLECTION itself, you're going to have to supply a particular USER_ID in order for that request to process correctly. Because you're using this action to login, this is not what you need. See http://guides.rubyonrails.org/routing.html#nested-resources
What you need to do instead is specify this route for the COLLECTION (ie: users/login
):
resources :users do
collection do
post 'login'
end
end
Then, in your form, change your form tag to say :controller => 'users', :action => 'login'
.
Finally, in your controller you'll need to specify a login action. In this case it can be as simple as:
def login
redirect_to users_path
end
All that will do is receive the POST and redirect to the index. However, if you want the params from your form to stick you'll need to process them in the LOGIN action. They won't persist and be available to your INDEX action after a redirect.
I hope this clears things up for you. Good luck!
Your problem lies in your routes.rb. Have a look here. The example is very clear:
resources :photos do
member do
get 'preview'
end
end
Description: "This will recognize /photos/1/preview with GET".
So, back to your code: the post login
line doesn't lead to where you intend to.
Instead the post request is directed to the 'create' view, because that's what you asked by typing resources :users
(see here).
Because it's not properly saved it redirects to the 'new' view, beacause of:
else
format.html { render :action => "new" }
So what solution? Here are some tracks:
- check your logs, they should be the resource to debug
- use rails s --debugger to put breakpoints and check your variables
- check your params, I don't understand why you rely on
params[:project]
to create your new User.
精彩评论