嵌套form_for的Rails路由错误

Inc*_*982 2 routing ruby-on-rails-3 ruby-on-rails-3.1

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

= form_for @comment, :url_for => { :action => "create", :controller => "comments"}, :method => :post
Run Code Online (Sandbox Code Playgroud)

我的佣金路线:

                   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"}
Run Code Online (Sandbox Code Playgroud)

错误:

undefined method `comments_path' for #<#<Class:0x007fed2c713128>:0x007fed2c71cc78>
Run Code Online (Sandbox Code Playgroud)

如果我将表格命名为:

= form_for [:trunk_root, @comment], :url_for => { :action => "create", :controller => "comments"}, :method => :post do |f|
Run Code Online (Sandbox Code Playgroud)

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

No route matches {:controller=>"comments", :format=>nil}
Run Code Online (Sandbox Code Playgroud)

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

更新:

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

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

Undefined method 'root_comments_path'
Run Code Online (Sandbox Code Playgroud)

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

= form_for [@trunk, @root, @comment] do |f| 
Run Code Online (Sandbox Code Playgroud)

< - 我得到'未定义的方法`politics_root_comments_path''..我认为......这可能是有道理的......因为我失败了我必须尝试你最明确的版本:

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

确实有用......所以我不太确定如何做到这一点......对我来说奇怪的是我在路线的同一深度上有另一个嵌套资源"照片"我是能够使用= form_for [:trunk_root,@ photo],:html => {:class =>'root_form'}做| f | ..但这里出于某种原因我不能......反正我' d说你给了我足够的理解100%,但我认为我从20%理解到50%理解.我现在知道id对路由很重要,而且命名助手需要访问它们.我介绍了url_helper的工作原理,但是我需要阅读更多信息,以便充分了解它.我现在也能够以更长的形式构建适当的路线,至少可以解决这种棘手的情况.所以谢谢 :)

Rya*_*igg 10

TL; DR您需要在URL中指定a :trunk_id和a root_id,或者form_for像这样使用:

<%= form_for [@trunk, @root, @comment] do |f| %>
Run Code Online (Sandbox Code Playgroud)

Rails正在尝试从您提供的哈希中构建一个URL,但该哈希与其路由表中的任何内容都不匹配.你可以这样做:

{ :controller => "comments", :action => "create", :trunk_id => trunk.id, :root_id => root.id }
Run Code Online (Sandbox Code Playgroud)

但这真的有点儿了;博士.

更酷的方法是:

trunk_root_comments_path(trunk, root)
Run Code Online (Sandbox Code Playgroud)

分别在哪里trunk,rootTrunkRoot实例.

现在,如果你想变得超级邪恶,那就这样做:

<%= form_for [trunk, root, comment] do |f| %>
Run Code Online (Sandbox Code Playgroud)

科学!

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

Rails首先认识到我们正在使用form_for数组而我们的意思是业务.Rails使用传入的数组并从中构建一个URL.它通过使用路由定义的路由助手来实现.不幸的是,你已经以一种有趣的方式定义了你的路线,但这并不好玩,但不要害怕!我们可以解决这个问题

您可以这样做的方式是config/routes.rb:

post '/t/:trunk_id/r/:root_id/comments'
Run Code Online (Sandbox Code Playgroud)

而是把这个:

post '/t/:trunk_id/r/:root_id/comments', :as => "trunk_root_comments"
Run Code Online (Sandbox Code Playgroud)

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

match '/t/:trunk_id/r/:root_id/comments', :via => :post
Run Code Online (Sandbox Code Playgroud)

哪个应该成为这个:

match '/t/:trunk_id/r/:root_id/comments', :via => :post, :as => "trunk_root_comments"
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,你现在都没有一个,而是由路由定义的两个(!!)路径助手.这些是trunk_root_comments_pathtrunk_root_comments_url.这些方法的名称对于我要向您解释的内容非常重要.请注意!

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

<%= form_for [trunk, root, comment] do |f| %>
Run Code Online (Sandbox Code Playgroud)

Rails知道我们正在使用一个数组,因为它可以看到它.它对这个阵列的作用可能看起来很神奇,但事实并非如此.

Rails将获取此数组的每个元素,并从不同的部分构建一个路由助手方法名称.这实际上不是其中的一部分form_for,而是另一种url_for可以单独使用的方法:

 url_for([trunk, root, comment])
Run Code Online (Sandbox Code Playgroud)

在开始时,生成的路由助手方法名称url_for只是一个空数组([]).没什么特别的.

但随后发生的事情特别!

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

Rails会知道这一点,所以将路由助手变成这样:[:trunk].

第二元件将是一个持久实例的的Root类.Rails也知道这个(该死的,Rails很聪明!)然后将它附加到阵列,将其转换为[:trunk, :root].真棒.

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

[:trunk, :root, :comments]
Run Code Online (Sandbox Code Playgroud)

现在看看我要去哪里?

现在,Rails已经完成它的事物(或,如果你喜欢),它将这三个部分一起加入这样的:trunk_root_comments,只是很好的措施,它会放_path于它的结束,把它变成了最终的trunk_root_comments_path帮手.

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

trunk_root_comments_path(:trunk_id => trunk.id, :root_id => root_id)
Run Code Online (Sandbox Code Playgroud)

这会生成资源的完整路径,如下所示:

/t/:trunk_id/r/:root_id/comments
Run Code Online (Sandbox Code Playgroud)

bam!完整的循环!这就是Rails知道生成URL的方式,你不必再使用丑陋的哈希了.

成功!