Rails的:通过形式创造新的记录时
比方说,我使用的是形式和标准的Rails宁静控制器,它看起来像这样创建一个新的Foo确认后网址失败:Rails的:通过形式创造新的记录时
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时,我在example.com/foos/new
,如果我提交表单并正确保存,我在example.com/foos
显示索引操作。但是,如果表单未被正确填充,表单会再次呈现并显示错误消息。这是纯粹的香草。
但是,如果显示错误,表单页面将呈现,但URL将为example.com/foos
,因为CREATE操作发布到该URL。然而,人们希望在example.com/foos
找到Foos#索引,而不是他们刚刚提交的表单中添加了错误消息。
这似乎是Rails的标准行为,但它没有很多道理给我。显然,我可以重定向到新的而不是从创建操作中渲染新的,但与此相关的问题是错误消息等将随着部分完整的Foos在内存中丢失。
对于这个问题,是否有一个干净的解决方案,当他们提交的新Foo表单中有错误时,这种方式可以将人员送回example.com/foos/new
?
谢谢!
你可以挂接到铁轨通过在初始化添加此路由: https://gist.github.com/903411
然后只要把经常资源在你的routes.rb:
resources :users
应该制定的路线和您的行为正在找。
你可以使用Rack::Flash来存储您在用户的会话想要的参数,然后重定向到您的表单URL。
def create
@foo = Foo.new(params[:foo])
if @foo.save
redirect_to foos_path, :notice => 'Created a foo.'
else
flash[:foo] = params[:foo]
flash[:errors] = @foo.errors
redirect_to new_foo_path #sorry - can't remember the Rails convention for this route
end
end
def new
# in your view, output the contents of flash[:foo]
@foo = Foo.new(flash[:foo])
end
如果您关心哪些URL将显示,您可以手动设置路由。你想要的东西,你可以有一个GET
到/foos/new
渲染你的形式,和POST
相同的URL做创作:
map.with_options :controller => :foos do |foo|
foo.new_foo '/foos/new', :conditions => {:method => :get}, :action => :new
foo.create_foo '/foos/new', :conditions => {:method => :post}, :action => :create
foo.foos '/foos', :conditions => {:method => :get}, :action => :index
end
这应该不需要到控制器的任何变化工作(!耶) - 所有来自你的例子的三个动作被照顾。少数免责声明:
- 这是基于我的2.3.8应用程序的路由 - 某些语法(语义?)更改可能需要将其转换为Rails 3路由样式。
- 我尝试混合使用
map.resources
路由的这种风格已经可怕的失败 - 除非你比我更熟悉,或者Rails 3路由是更好的(既容易实现),你必须为每个路线做到控制器。 - 最后,不要忘了加
/:id
,(.:format)
等,到需要它们的路径(在这个例子中没有,但看到#2)。
希望这有助于!
编辑:最后一两件事 - 你需要硬编码的URL在form_for
帮手上/foos/new.html.erb
。只需添加:url => create_foo_path
即可,因此Rails不会尝试发布到/foos
,默认情况下(可能会更改模型中的创建URL,但我不知道它是否有)。
要回答另一个回答您的评论:
我不知道是否有一种方法,而完全不重写控制器,告诉你想要的网址导轨相匹配的渲染模板,而不是调用它的控制器操作。
我不这么认为; URL直接绑定到路由,绑定到控制器和动作对 - 渲染层完全不会触及它。
要回答您原来的问题,这里是从another similar question信息我回答。
正如您看到的,默认情况下,当你指定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"}
这听起来像你想要更多的东西是这样的:
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"}
虽然不建议,你可以得到这个结果与下列路线:
resources :things, :except => [ :create ] do
post "create" => "things#create", :as => :create, :path => 'new', :on => :collection
end
您还需要修改表单以使其POST到正确的路径。
好吧,这几乎可以回答我的问题(不,这并不是一个很好的干净方式)。真正让我困扰的是,当你的新纪录未通过验证时,你所得到的URL不是正在查看的页面的正确URL。如果您重新加载该页面,则不会获得相同的页面。如果你问我,这看起来像是一个糟糕的内部设计决定,但是哦。因为我刚刚获得奖励,所以我会稍微延长一段时间 - 以防其他人有任何其他想法。谢谢! – Andrew 2011-04-03 03:33:20
可以理解。我支持网址很重要的想法,我可以理解这种沮丧。我想知道这个选择背后是否有一些推理。但是,请记住,这不是真正的REST。有一个名为[RESTful Best Practices](http://www.slideshare.net/calamitas/restful-best-practices)的幻灯片,这当然让我想到了。 – 2011-04-03 03:56:44
不幸的是,这个解决方案没有验证错误。 – WojciechKo 2015-08-29 23:42:07
这实际上是非常有用的,因为虽然它是一种戏剧性的黑客攻击,但它确实开放了测试配置rails应用程序的不同方法的可能性,我可能以后会制作一个gem,甚至提交考虑到rails core 。我喜欢这个想法,我会在稍后尝试。谢谢! – Andrew 2011-04-07 03:26:49
非常有用 - 但:是否有任何理由更新操作不使用编辑路径? – 2011-11-02 20:23:04