Rails:通过表单创建新记录时验证后的 URL 失败
假设我正在使用表单和标准 Rails 静态控制器创建一个新的 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
因此,如果我使用标准静态控制器(如上所述),那么当我创建 Foo 时,我位于 < code>example.com/foos/new,如果我提交表单并且正确保存,我将在 example.com/foos
显示索引操作。但是,如果表单未正确填写,则会再次呈现表单并显示错误消息。这都是普通的香草。
但是,如果显示错误,则将呈现表单页面,但 URL 将为 example.com/foos
,因为 CREATE 操作会发布到该 URL。然而,人们希望在 example.com/foos
找到 Foos#index,而不是他们现在刚刚提交的添加了错误消息的表单。
这似乎是 Rails 标准行为,但对我来说没有多大意义。显然,我可以重定向回 new,而不是从创建操作中渲染 new,但这样做的问题是错误消息等将与内存中部分完整的 Foos 一起丢失。
是否有一个干净的解决方案来解决这个问题,当人们提交的新 Foo 表单出现错误时,将他们送回 example.com/foos/new
?
谢谢!
Lets say I am creating a new Foo using a form and a standard Rails restful controller, which looks something like this:
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
So, if I use the standard restful controller (as above), then when I'm creating the Foo I am at example.com/foos/new
, and if I submit the form and it saves correctly I'm at example.com/foos
showing the index action. However, if the form is not filled correctly the form is rendered again and error messages are shown. This is all plain vanilla.
However, if errors are shown, the form page will be rendered but the URL will be example.com/foos
, because the CREATE action posts to that url. However, one would expect to find Foos#index at example.com/foos
, not the form they just submitted now with error messages added.
This seems to be Rails standard behavior, but it doesn't make a lot of sense to me. Obviously I could redirect back to new instead of rendering new from the create action, but the problem with that is the error messages etc. would be lost along with the partially complete Foos in memory.
Is there a clean solution for this problem, a way to send people back to example.com/foos/new
when there are errors in the new Foo form they submitted?
Thanks!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
回答您对另一个答案的评论:
我不这么认为; URL 直接与路由绑定,而路由与控制器和操作对绑定——渲染层根本不接触它。
要回答您原来的问题,请参阅以下信息:我回答了另一个类似的问题。
正如您所发现的,默认情况下,当您指定
resources :things
时,用于创建新事物的 POST 路径位于/things
。这是 rake 路由的输出:听起来你想要更多类似这样的东西:
虽然不推荐,但你可以通过以下路由获得此结果:
你还需要修改你的表单以使其 POST到正确的道路。
To answer your comment on another answer:
I don't think so; URLs are tied directly to routing, which is tied into a controller and action pair--the rendering layer doesn't touch it at all.
To answer your original question, here's information from another similar question I answered.
As you've found, by default when you specify
resources :things
, the POST path for creating a new thing is at/things
. Here's the output forrake routes
:It sounds like you want something more like this:
Although not recommended, you can get this result with the following route:
You would also need to modify your forms to make them POST to the correct path.
您可以通过在初始化程序中添加以下内容来挂钩 Rails 路由:
https://gist.github.com/903411
然后将常规资源放入你的routes.rb中:
它应该创建您正在寻找的路线和行为。
You could hook into rails routing by adding this in an initializer:
https://gist.github.com/903411
Then just put the regular resources in your routes.rb:
It should create the routes and behaviour you are looking for.
如果您担心要显示的 URL,则可以手动设置路由。对于您想要的内容,您可以使用
GET
来/foos/new
呈现您的表单,并使用POST
到同一 URL 来进行创建:这应该可以工作,而不需要对控制器进行任何更改(耶!) - 您的示例中的所有三个操作都已处理。一些免责声明:
map.resources
混合在一起,但失败了——除非你比我更熟悉这一点,或者 Rails 3 路由更好(两者都很容易实现),否则你将拥有对到控制器的每条路由执行此操作。/:id
、(.:format)
等添加到需要它们的路由中(本例中没有,但请参阅# 2)。希望这有帮助!
编辑:最后一件事 - 您需要在
/foos/new.html.erb
上的form_for
帮助程序中对 URL 进行硬编码。只需添加:url => create_foo_path
,因此Rails不会尝试发布到/foos
,默认情况下它会这样做(可能有一种方法可以更改模型中的创建URL,但我不这样做知道的话,如果有的话)。You can set up the routing manually, if you're that concerned about what URL is going to show. For what you want, you can have a
GET
to/foos/new
render your form, and aPOST
to the same URL do the creation:This should work without requiring any changes to your controller (yay!) - all three actions from your example are taken care of. The few disclaimers:
map.resources
have failed horribly - unless you're more familiar with this than me, or Rails 3 routing is better (both easily possible), you'll have to do this for every route to the controller./:id
,(.:format)
, etc. to the routes that need them (none in this example, but see #2).Hope this helps!
Edit: One last thing - you'll need to hard-code the URL in your
form_for
helper on/foos/new.html.erb
. Just add:url => create_foo_path
, so Rails doesn't try to post to/foos
, which it will by default (there might be a way to change the creation URL in the model, but I don't know of it, if there is one).您可以使用 Rack::Flash 在用户会话中存储所需的参数,然后重定向到您的表单网址。
You could use Rack::Flash to store the parameters you wanted in the user's session and then redirect to your form url.