嵌套form_for的Rails路由错误

时间:2011-12-07 06:30:25

标签: ruby-on-rails-3 routing ruby-on-rails-3.1

我现在已经被问了一千次但这对我没有帮助嘿:)我已经在这一个小时了。我的表格:

= 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|

应该根据rake路线制作路线trunk_root_comments_path ..这是正确的..我得到:

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

非常感谢帮助..已经看了好几个小时..

更新:

谢谢Ryan这么棒的答案!一个非常明确的解释,我只是“扔东西”,现在至少我理解得更好。我实际上已经在我的佣金路线中提供了'trunk_root_comments_path',并且我尝试过你提到的几种组合,但我并没有真正讨厌我所缺少的东西,所以你帮了忙。我正在使用Mongo,我实际上没有Trunk模型,我只有一个名为@root.trunk的根属性,虽然我有一个中继控制器,因此它是我的路由的一部分(也许是一个坏主意idk) 。

所以我尝试了你的TLDR,它说错误:

Undefined method 'root_comments_path'

..因为没有Trunk模型存在,我假设?..所以我让@trunk等于正确的id

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

&lt; - 我得到'未定义的方法`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 =&gt; {:class =&gt; 'root_form'}做| f | ..但是由于某种原因,我不能......反正我会说你给了我足够的理解100%,但我想我从20%的理解到50%的理解..我现在知道id对路由很重要,而命名的助手需要访问它们。我介绍了url_helper的工作原理,但是我需要阅读更多信息,以便充分了解它。我现在也能够以更长的形式构建适当的路线,至少可以解决这种棘手的情况。谢谢你:)。

2 个答案:

答案 0 :(得分: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; dr

更酷的方法是:

trunk_root_comments_path(trunk, root)

trunkroot分别是TrunkRoot个实例。

现在,如果你想成为 super-wicked-cool ,那就这样做:

<%= 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将获取此数组的每个元素,并从不同的部分构建路由助手方法 name 。这实际上不是form_for的一部分,而是另一种名为url_for的方法,可以单独使用:

 url_for([trunk, root, comment])

最初,url_for生成的路由助手方法名称只是一个空数组([])。没什么特别的。

但接下来发生的事情特别的!

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

Rails会知道这一点,因此会将路由助手变为:[:trunk]

第二个元素将是Root类的持久化实例。 Rails也知道这个(该死的,Rails是 smart !)然后将它附加到数组,将其转换为[:trunk, :root]。真棒。

然后Rails检查第三个(也是最后一个)元素。它看到(在这种情况下)它是一个非持久化元素,即它尚未保存到数据库中。 Rails以不同的方式对待它,而是将[:comments]附加到数组,将其转换为:

[:trunk, :root, :comments]

现在看看我现在要去哪里?

现在Rails做了它的事情(或 thang ,如果你愿意的话)它将这三个部分加在一起: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

bam!全圈!这就是Rails知道生成URL的方式,你不必再使用丑陋的哈希了。

成功!

答案 1 :(得分:0)

不确定您是否设置了此路线,但请尝试:

= form_for @comment, :url => trunk_root_comments_path