嵌套资源的 form_for

我有一个关于 form _ for 和嵌套资源的两部分问题。假设我正在写一个博客引擎,我想把一条评论与一篇文章联系起来。我将嵌套资源定义如下:

map.resources :articles do |articles|
articles.resources :comments
end

评论表单位于文章的 show.html.erb 视图中,位于文章本身之下,例如:

<%= render :partial => "articles/article" %>
<% form_for([ :article, @comment]) do |f| %>
<%= f.text_area :text %>
<%= submit_tag "Submit" %>
<%  end %>

这样会出现一个错误,“调用 id 为 nil,这样会出错等等”,我也尝试过

<% form_for @article, @comment do |f| %>

它呈现正确,但是将 f.text _ area 与文章的“ text”字段而不是注释字段联系起来,并为该文本区域中的 artile.text 属性呈现 html。看来我也搞错了。我想要的是一个表单,它的“提交”将调用 CommentsController 上的 create 操作,在 params 中包含 article _ id,例如对/article/1/comments 的发帖请求。

我的问题的第二部分是,首先创建注释实例的最佳方式是什么?我正在 ArticlesController 的 show 操作中创建一个@注释,因此一个注释对象将在 form _ for helper 的范围内。然后在 CommentsController 的 create 操作中,我使用 form _ for 传入的参数创建新的@comments。

谢谢!

109076 次浏览

您不需要在表单中执行特殊的操作。你只需要在 show 动作中正确地构建评论:

class ArticlesController < ActionController::Base
....
def show
@article = Article.find(params[:id])
@new_comment = @article.comments.build
end
....
end

然后在文章视图中为它制作一个表单:

<% form_for @new_comment do |f| %>
<%= f.text_area :text %>
<%= f.submit "Post Comment" %>
<% end %>

默认情况下,此注释将转到 CommentsControllercreate操作,然后您可能想将 redirect :back放入该操作中,以便将其路由回 Article页面。

一定要在控制器中创建两个对象: @post@comment,例如:

@post = Post.find params[:post_id]
@comment = Comment.new(:post=>@post)

接下来的观点是:

<%= form_for([@post, @comment]) do |f| %>

一定要在 form _ for 中显式定义数组,而不要像上面那样只用逗号分隔。

特拉维斯 R 是正确的。(我希望我可以支持你。)我刚刚得到这个工作自己。与这些路线:

resources :articles do
resources :comments
end

你会得到这样的路径:

/articles/42
/articles/42/comments/99

路由到控制器

app/controllers/articles_controller.rb
app/controllers/comments_controller.rb

正如它在 http://guides.rubyonrails.org/routing.html#nested-resources中所说的,没有特殊的名称空间。

但是偏旁和形式变得棘手。注意方括号:

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

最重要的是,如果你想要一个 URI,你可能需要这样的东西:

article_comment_path(@article, @comment)

或者:

[@article, @comment]

http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects所述

例如,在为迭代提供 comment_item的集合部分中,

<%= link_to "delete", article_comment_path(@article, comment_item),
:method => :delete, :confirm => "Really?" %>

Jamuraa 所说的可能在文章的语境中起作用,但是在其他方面对我没有起作用。

有很多关于嵌套资源的讨论,例如 http://weblog.jamisbuck.org/2007/2/5/nesting-resources

有趣的是,我刚刚了解到大多数人的单元测试实际上并不是测试所有的路径。当人们听从 JamisBuck 的建议时,他们最终会得到两种获取嵌套资源的方法。他们的单元测试通常会得到/发布到最简单的:

# POST /comments
post :create, :comment => {:article_id=>42, ...}

为了测试他们可能更喜欢的路线,他们需要这样做:

# POST /articles/42/comments
post :create, :article_id => 42, :comment => {...}

我之所以学到这一点,是因为我的单元测试开始失败,当我从这里切换到:

resources :comments
resources :articles do
resources :comments
end

回到这里:

resources :comments, :only => [:destroy, :show, :edit, :update]
resources :articles do
resources :comments, :only => [:create, :index, :new]
end

我认为有重复的路线和错过一些单元测试是可以的。(为什么要测试?因为即使用户从未看到副本,您的表单也可能会引用它们,可能是隐式引用,也可能是通过指定的路由引用。)不过,为了尽量减少不必要的重复,我建议这样做:

resources :comments
resources :articles do
resources :comments, :only => [:create, :index, :new]
end

很抱歉回答得这么长。我认为没有多少人意识到其中的微妙之处。