Rails路由到错误的URL

lka*_*htz 4 ruby-on-rails

我在非用户模型的视图中写了一个表单,允许访问者登录.我想先看看这是否有效.所以我让动作"索引"进行测试.

<%form_tag(:controller=>"users",:action=>"index")  do %>
  Name: <%=text_field_tag "name"  %><br>    
  Password: <%=password_field_tag "password" %><br>
  <%=submit_tag "Login"  %>
<% end -%>
Run Code Online (Sandbox Code Playgroud)

令人惊讶的是,rails路由将页面定向到"新"视图,而浏览器导航栏仍然显示:

http://0.0.0.0:3000/users
Run Code Online (Sandbox Code Playgroud)

刷新页面时,它会显示正常的"索引"页面.

为什么会这样?

更令人毛骨悚然的是,当我更改:action上面的代码时:action=>"new",屏幕显示"路由错误".当我刷新它时,它呈现正常的"新"视图.

users_controller.rb如下:

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
Run Code Online (Sandbox Code Playgroud)

我的routes.rb如下:

Testdrive::Application.routes.draw do

  resources :users do
    member do
      post 'login'
    end
  end
  resources :cars 
Run Code Online (Sandbox Code Playgroud)

And*_*rew 5

Apneadiving的答案是正确的,但我认为澄清一些事情很重要:

您试图让用户访问哪个页面?听起来您希望用户进入索引页面(您对用户登陆新页面感到惊讶).

首先:您应该了解您所提出的HTTP请求类型与控制器指向浏览器的位置之间的关系.请参阅http://guides.rubyonrails.org/routing.html#crud-verbs-and-actions

基本上你的表单是向/users网址提交POST请求.Controller始终将POSTS路由到此地址以进行CREATE操作.因此,正如Apneadiving所解释的那样,你发送的post params并不是CREATE期待的那些,所以save失败并且你被重定向到users/new

现在,我看到你指定的形式::controller => 'users', :action => 'index'.所以,这就是我看到你希望人们登陆索引页面的地方.但是,您需要了解的是,Rails表单助手不会神奇地链接到控制器层.

第二:知道Rails中的信息流基本上是单向的:模型中的东西可以转到控制器,但不是其他方式.来自控制器的东西可以进入视图,但不是其他方式.

控制器可以从用户接收的唯一内容是HTTP请求.当您使用表单标记帮助程序时,您只是使用快捷方式来定义HTML 元素的属性actionmethod属性form.见http://www.w3.org/TR/html401/interact/forms.html#h-17.13

因此,即使您指定:action => 'index',您的表单仍然发送POST请求(默认情况下形成POST).控制器不知道你是否意味着该人的请求命中索引操作,它只知道它在/usersURL上收到了POST而不是GET .因此,它将请求路由到CREATE操作.

这就是REST的全部意义所在.

解决方案:

您需要使用尚未预定义的操作.在您的路线中,当您放置时,您似乎尝试这样做:

resources :users do
  member do
    post 'login'
  end
end
Run Code Online (Sandbox Code Playgroud)

此代码将正确接受POST请求users/123/login.

但是,因为您在用户集合的MEMBER而不是COLLECTION本身上指定了此项,所以您必须提供特定的USER_ID才能使该请求正确处理.因为您正在使用此操作进行登录,所以这不是您所需要的.请参阅http://guides.rubyonrails.org/routing.html#nested-resources

你需要做的是为COLLECTION指定这条路线(即:)users/login:

resources :users do
  collection do
    post 'login'
  end
end
Run Code Online (Sandbox Code Playgroud)

然后,在您的表单中,将表单标记更改为say :controller => 'users', :action => 'login'.

最后,在您的控制器中,您需要指定登录操作.在这种情况下,它可以很简单:

def login
  redirect_to users_path
end
Run Code Online (Sandbox Code Playgroud)

所有这一切都将接收POST并重定向到索引.但是,如果您希望表单中的params粘贴,则需要在LOGIN操作中处理它们.在重定向后,它们不会持久存在并可用于您的INDEX操作.

我希望这能为你解决问题.祝好运!