开发者

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.
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜