Rails:通过表单创建新记录时验证失败后的URL

And*_*rew 19 url controller ruby-on-rails view ruby-on-rails-3

让我们说我正在使用一个表单和一个标准的Rails restful控制器创建一个新的Foo,它看起来像这样:

class FoosController < ApplicationController
  ...
  def index
    @foos = Foo.all
  end

  def new
    @foo = Foo.new
  end

  def create
    @foo = Foo.create(params[:foo])
    if @foo.save
      redirect_to foos_path, :notice => 'Created a foo.'
    else
      render 'new'
    end
  end
  ...
end
Run Code Online (Sandbox Code Playgroud)

所以,如果我使用标准的REST风格的控制器(如上),然后当我创建我的富example.com/foos/new,如果我提交表单,它可以正确保存我在example.com/foos显示索引操作.但是,如果未正确填充表单,则会再次呈现表单并显示错误消息.这一切都是普通的香草.

但是,如果显示错误,将呈现表单页面,但URL将是example.com/foos,因为CREATE操作会发布到该URL.但是,人们期望找到Foos #index at example.com/foos,而不是他们刚刚提交的表单,并添加了错误消息.

这似乎是Rails的标准行为,但它对我来说并没有多大意义.显然我可以重定向回new而不是从create动作渲染new,但问题是错误消息等会随着内存中部分完整的Foos而丢失.

有没有一个干净的解决方案来解决这个问题,example.com/foos/new当他们提交的新Foo表单中存在错误时,可以将人们发送回去吗?

谢谢!

Mic*_*ley 9

回答你对另一个答案的评论:

我想知道是否有一种方法,根本没有重写控制器,告诉rails你希望URL匹配渲染的模板,而不是调用它的控制器动作.

我不这么认为; URL直接绑定到路由,路由绑定到控制器和操作对 - 渲染层根本不接触它.

为了回答你原来的问题,这里是我回答的另一个类似问题的信息.


正如您所发现的那样,默认情况下,当您指定时resources :things,用于创建新事物的POST路径为/things.这是输出rake routes:

    things GET    /things(.:format)          {:action=>"index", :controller=>"things"}
           POST   /things(.:format)          {:action=>"create", :controller=>"things"}
 new_thing GET    /things/new(.:format)      {:action=>"new", :controller=>"things"}
edit_thing GET    /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
     thing GET    /things/:id(.:format)      {:action=>"show", :controller=>"things"}
           PUT    /things/:id(.:format)      {:action=>"update", :controller=>"things"}
           DELETE /things/:id(.:format)      {:action=>"destroy", :controller=>"things"}
Run Code Online (Sandbox Code Playgroud)

听起来你想要更像这样的东西:

create_things POST   /things/new(.:format)      {:action=>"create", :controller=>"things"}
       things GET    /things(.:format)          {:action=>"index", :controller=>"things"}
    new_thing GET    /things/new(.:format)      {:action=>"new", :controller=>"things"}
   edit_thing GET    /things/:id/edit(.:format) {:action=>"edit", :controller=>"things"}
        thing GET    /things/:id(.:format)      {:action=>"show", :controller=>"things"}
              PUT    /things/:id(.:format)      {:action=>"update", :controller=>"things"}
              DELETE /things/:id(.:format)      {:action=>"destroy", :controller=>"things"}
Run Code Online (Sandbox Code Playgroud)

虽然不推荐,但您可以通过以下路径获得此结果:

resources :things, :except => [ :create ] do
  post "create" => "things#create", :as => :create, :path => 'new', :on => :collection
end
Run Code Online (Sandbox Code Playgroud)

您还需要修改表单以使其POST到正确的路径.

  • 好吧,这几乎回答了我的问题(不,这并不是一个很好的干净方法).真正困扰我的是,当您的新记录验证失败时,您获得的URL不是您正在查看的页面的正确URL.如果您重新加载该页面,则不会获得相同的页面.如果你问我,这似乎是在轨道内部的一个糟糕的设计决定,但哦,好吧.因为我只是给了它一笔赏金,所以我会把它打开一点时间 - 以防其他人有任何其他想法.谢谢! (3认同)

Mar*_*dré 4

您可以通过在初始化程序中添加以下内容来挂钩 Rails 路由: https://gist.github.com/903411

然后只需将常规资源放入您的routes.rb中即可:

resources :users
Run Code Online (Sandbox Code Playgroud)

它应该创建您正在寻找的路线和行为。

  • 非常有用 - 但是:更新操作不使用编辑路径有什么原因吗? (2认同)