2011-12-07 72 views
2

我现在已经被问了上千次,但这并不帮助我嘿:)我一直在这一个小时。我的形式:Rails路由错误的嵌套form_for

= form_for @comment, :url_for => { :action => "create", :controller => "comments"}, :method => :post 

我耙路线:

    POST /t/:trunk_id/r/:root_id/comments(.:format)   {:action=>"create", :controller=>"comments"} 
trunk_root_comment GET /t/:trunk_id/r/:root_id/comments/:id(.:format)  {:action=>"show", :controller=>"comments"} 

错误:

undefined method `comments_path' for #<#<Class:0x007fed2c713128>:0x007fed2c71cc78> 

如果我的名字空间的形式:

= form_for [:trunk_root, @comment], :url_for => { :action => "create", :controller => "comments"}, :method => :post do |f| 

应使路由trunk_root_comments_path ..这是正确的acc奥尔丁的耙路线的..我得到:

No route matches {:controller=>"comments", :format=>nil} 

帮助是非常赞赏..一直在寻找这几个小时..

UPDATE:

感谢您瑞安这样一个伟大的答案!一个非常清楚的解释,我只是在'扔东西',现在至少我理解得更好。实际上,我的耙路线中已经有了'trunk_root_comments_path',并且我尝试了一些你提到的组合,但是我没有真正地琢磨我错过了什么,所以你的帮助。我使用的是Mongo,实际上我没有Trunk模型,我只有一个名为@ root.trunk的属性,虽然我有一个trunk控制器,因此它是我路线的一部分(也许是一个糟糕的主意idk) 。

所以,我想你的TLDR,它说错误:

Undefined method 'root_comments_path' 

..不会造成干线模型存在,我想..所以我做了@trunk刚好等于正确的ID与

= form_for [@trunk, @root, @comment] do |f| 

< - 和我“未定义的方法`politics_root_comments_path”。我盘算好..这可能是有道理..因为我失败,我必须一试你最明确的版本:

= form_for @comment, :url => (trunk_root_comments_path(:trunk_id => @root.trunk, :root_id => @root.id)) do |f| 

肯定这个工作......所以我不太确定如何做到这一点比这短..对我来说奇怪的是我有另一个嵌套资源“照片”在路线相同的深度级别我可以通过= form_for [:trunk_root,@photo],:html => {:class =>'root_form'} do | f | ..但是出于某种原因,我不能..无论如何,我会说你给我足够的理解100%,但我认为我从20%的理解到50%的理解。现在我知道id对路由很重要,并且指定的助手需要访问它们。我介绍了url_helper是如何工作的,但是需要阅读更多内容才能真正完成我的想法。我现在也能够以更长的形式构建适当的路线,至少可以解决这种棘手的情况。所以,谢谢:)

+0

忽略我的答案(至少一段时间:))你的路线如何设置? – jlundqvist

回答

10

TL; DR你需要指定您的网址既是:trunk_idroot_id或使用form_for这样的:

<%= form_for [@trunk, @root, @comment] do |f| %> 

Rails试图从你提供的哈希构建一个URL,但是这个哈希不匹配其路由表中的任何内容。你可以这样做:

{ :controller => "comments", :action => "create", :trunk_id => trunk.id, :root_id => root.id } 

但是,这真的有点TL;博士

冷却器方式做到这一点是这样的:

trunk_root_comments_path(trunk, root) 

trunkroot分别为TrunkRoot实例。

现在,如果你想成为超级邪恶爽,像这样做:

<%= form_for [trunk, root, comment] do |f| %> 

科学!

那么这是如何工作的?小学,我亲爱的:

Rails的第一个认识到,我们使用form_for使用数组和我们是认真的。 Rails使用传入的数组并从中构建一个URL。它通过使用由路由定义的路由帮助器来完成此操作。不幸的是,你已经用有趣的方式定义了你的路线,但这并不好玩,但并不害怕!我们可以解决这个问题。

你能做到这一点的方式是这样的,你有这样的config/routes.rb

post '/t/:trunk_id/r/:root_id/comments' 

而是把这个:

post '/t/:trunk_id/r/:root_id/comments', :as => "trunk_root_comments" 

您可能或者已经有这样的:

match '/t/:trunk_id/r/:root_id/comments', :via => :post 

这应该成为这样:

match '/t/:trunk_id/r/:root_id/comments', :via => :post, :as => "trunk_root_comments" 

无论哪种方式,你现在得到不是一个,而是两(!!)通过路由定义路径帮手。这些分别是trunk_root_comments_pathtrunk_root_comments_url这些方法的名称对于我即将向您解释的内容非常重要。请注意!

所以,回到我们的小form_for电话:

<%= form_for [trunk, root, comment] do |f| %> 

的Rails知道我们使用数组,因为它可以看到它。它与这个阵列做什么可能似乎像魔术,但不是真的。

Rails将把这个数组的每个元素并建立一个路由帮助器方法名称由不同部分组成。这不是真正的form_for一部分,但另一种方法叫做url_for,您可以通过单独使用:

url_for([trunk, root, comment]) 

在开始的时候,通过url_for生成此路由helper方法名称只是一个空数组([])。没有什么特别的。

但是接下来会发生什么特!

第一个元素将是Trunk类的持久实例。通过“坚持”我的意思是这是一个对象,将直接映射到数据库中的记录。 Yay ORMs!

Rails会知道这一点,所以会将路由帮助程序变为:[:trunk]

第二个元素将是Root类的持久实例。 Rails也知道这一点(该死的,Rails是smart!),然后将它添加到数组中,将它变成[:trunk, :root]。真棒。

然后通过Rails检查第三个(也是最后一个)元素。它认为(在这种情况下)它是一个非持久性元素,即它没有被保存到数据库中。 Rails的对待这个不同,反而会追加[:comments]到数组,把它变成这样:

[:trunk, :root, :comments] 

看到我这个现在要去哪里?

现在Rails已经完成它的东西(或,如果你喜欢),它将这三个部位连接在一起,就像这样:trunk_root_comments,只是很好的措施它会让_path在它的结束,转向它进入最后的trunk_root_comments_path帮手。

然后!男人,然后...... Rails调用这个方法并传递它的参数!就像这样:

trunk_root_comments_path(:trunk_id => trunk.id, :root_id => root_id) 

这产生于资源的完整路径是这样的:

/t/:trunk_id/r/:root_id/comments 

而且嘭!整圈!这就是Rails知道如何生成URL并且不必再使用丑陋的哈希。

成功!

+0

在非常好的答案。在这里阅读你的动物是非常好的。 – lucapette

+1

谢谢瑞恩!多好的答案。希望更多有路由问题的人看到这一点。得到它的工作,虽然也许不像我想要的tldr,但你可以看到我的更新的细节。谢谢 :) – Inc1982

0

不知道你是否有这条路线设置,但尝试:

= form_for @comment, :url => trunk_root_comments_path 
+0

无法正常工作,路由需要同时传递或传递此表单的请求中可用的':trunk_id'和':root_id'参数。 –

+0

哦,我完全错过了。 – jlundqvist

+0

感谢jlundqvist的回应。我上面更新了我的答案,以反映我是如何使用Ryan Bigg的建议之一来工作的。 – Inc1982