【问题标题】:Rails Routing Error for nested form_for嵌套 form_for 的 Rails 路由错误
【发布时间】:2011-12-07 06:30:25
【问题描述】:

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

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

我的 rake 路线:

                   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_cmets_path..根据rake路由是正确的..我得到:

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

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

更新:

感谢 Ryan 提供了这么好的答案!对我只是“扔东西”的东西的一个非常清楚的解释,现在至少我理解得更好了。实际上,我的 rake 路由中已经有 'trunk_root_cmets_path' 可用,并且我尝试了你提到的几种组合,但我并没有真正了解我所缺少的东西,所以你提供了帮助。我正在使用 Mongo,实际上我没有 Trunk 模型,我只有一个名为 @root.trunk 的根属性,尽管我有一个 Trunk 控制器,因此它是我路由的一部分(可能是个坏主意 idk) .

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

Undefined method 'root_comments_path'

.. 因为不存在 Trunk 模型,我假设?.. 所以我让 @trunk 与

的正确 id 相等
= form_for [@trunk, @root, @comment] do |f| 

= 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 的工作原理,但我认为需要阅读更多内容才能真正完全理解它。我现在也能够以更长的形式构建适当的路线,至少可以通过这种棘手的情况。所以谢谢你:)

【问题讨论】:

  • 忽略我的回答(至少暂时 :))您的路线是如何设置的?

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


【解决方案1】:

TL;DR 您需要在 URL 中同时指定 :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 实例。

现在,如果你想成为 超级邪恶的酷,就这样做吧:

<%= 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 类的持久实例。 “持久化”是指它是一个将直接映射到数据库中记录的对象。耶 ORM!

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

第二个元素将是Root 类的持久实例。 Rails 也知道这一点(该死,Rails 是智能!),然后会将其附加到数组中,将其转换为[:trunk, :root]。太棒了。

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

[:trunk, :root, :comments]

看看我现在要做什么了吗?

现在 Rails 已经完成了它的事情(或者 thang,如果你愿意的话)它将像这样将这三个部分连接在一起:trunk_root_comments,为了更好的衡量,它会将@987654354 @ 在它的末尾,把它变成最后的 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 的方式,您不必再使用丑陋的哈希。

成功了!

【讨论】:

  • 谢谢瑞恩!多么棒的答案。希望更多有路由问题的人看到这一点。得到它的工作,虽然可能不像我想要的那样 tldr 但你可以查看我的更新以获取详细信息。谢谢:)
【解决方案2】:

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

= form_for @comment, :url => trunk_root_comments_path

【讨论】:

  • 不起作用,路由需要 :trunk_id:root_id 参数传入或在呈现此表单的请求中可用。
  • 感谢 jlundqvist 的回复。我更新了上面的答案,以反映我如何使用 Ryan Bigg 的建议之一。
猜你喜欢
  • 2011-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-04
  • 1970-01-01
  • 2015-07-28
相关资源
最近更新 更多