Ruby-on-rails 带有嵌套资源的 form_for

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2034700/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 22:07:35  来源:igfitidea点击:

form_for with nested resources

ruby-on-railsform-fornested-resources

提问by Dave Sims

I have a two-part question about form_for and nested resources. Let's say I'm writing a blog engine and I want to relate a comment to an article. I've defined a nested resource as follows:

我有一个关于 form_for 和嵌套资源的两部分问题。假设我正在编写一个博客引擎,我想将评论与文章相关联。我已经定义了一个嵌套资源如下:

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

The comment form is in the show.html.erb view for articles, underneath the article itself, for instance like this:

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

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

This gives an error, "Called id for nil, which would mistakenly etc." I've also tried

这给出了一个错误,“为 nil 调用了 id,这会错误地等等。” 我也试过

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

Which renders correctly but relates f.text_area to the article's 'text' field instead of the comment's, and presents the html for the article.text attribute in that text area. So I seem to have this wrong as well. What I want is a form whose 'submit' will call the create action on CommentsController, with an article_id in the params, for instance a post request to /articles/1/comments.

它呈现正确但将 f.text_area 与文章的“文本”字段而不是评论的字段相关联,并在该文本区域中显示 article.text 属性的 html。所以我似乎也有这个错误。我想要的是一个表单,它的“提交”将调用 CommentsController 上的创建操作,参数中有一个 article_id,例如对 /articles/1/comments 的发布请求。

The second part to my question is, what's the best way to create the comment instance to begin with? I'm creating a @comment in the show action of the ArticlesController, so a comment object will be in scope for the form_for helper. Then in the create action of the CommentsController, I create new @comment using the params passed in from the form_for.

我的问题的第二部分是,开始创建评论实例的最佳方法是什么?我在 ArticlesController 的 show 操作中创建了一个 @comment,因此一个评论对象将在 form_for 助手的范围内。然后在 CommentsController 的创建操作中,我使用从 form_for 传入的参数创建新的 @comment。

Thanks!

谢谢!

回答by cdunn2001

Travis R is correct. (I wish I could upvote ya.) I just got this working myself. With these routes:

特拉维斯 R 是正确的。(我希望我能投票给你。)我自己才开始工作。通过这些路线:

resources :articles do
  resources :comments
end

You get paths like:

你得到的路径如下:

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

routed to controllers at

路由到控制器

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

just as it says at http://guides.rubyonrails.org/routing.html#nested-resources, with no special namespaces.

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

But partials and forms become tricky. Note the square brackets:

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

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

Most important, if you want a URI, you may need something like this:

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

article_comment_path(@article, @comment)

Alternatively:

或者:

[@article, @comment]

as described at http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

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

For example, inside a collections partial with comment_itemsupplied for iteration,

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

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

What jamuraa says may work in the context of Article, but it did not work for me in various other ways.

jamuraa 所说的可能适用于文章的上下文,但它在其他各种方式中对我不起作用。

There is a lot of discussion related to nested resources, e.g. http://weblog.jamisbuck.org/2007/2/5/nesting-resources

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

Interestingly, I just learned that most people's unit-tests are not actually testing all paths. When people follow jamisbuck's suggestion, they end up with two ways to get at nested resources. Their unit-tests will generally get/post to the simplest:

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

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

In order to test the route that they may prefer, they need to do it this way:

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

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

I learned this because my unit-tests started failing when I switched from this:

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

resources :comments
resources :articles do
  resources :comments
end

to this:

对此:

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

I guess it's ok to have duplicate routes, and to miss a few unit-tests. (Why test? Because even if the user never sees the duplicates, your forms may refer to them, either implicitly or via named routes.) Still, to minimize needless duplication, I recommend this:

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

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

Sorry for the long answer. Not many people are aware of the subtleties, I think.

对不起,答案很长。我想,没有多少人意识到其中的微妙之处。

回答by Travis Reeder

Be sure to have both objects created in controller: @postand @commentfor the post, eg:

确保在 controller:@post@commentpost 中创建了两个对象,例如:

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

Then in view:

那么在视图中:

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

Be sure to explicitly define the array in the form_for, not just comma separated like you have above.

确保在 form_for 中明确定义数组,而不仅仅是像上面那样用逗号分隔。

回答by jamuraa

You don't need to do special things in the form. You just build the comment correctly in the show action:

你不需要在表格中做特别的事情。您只需在 show 操作中正确构建评论:

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

and then make a form for it in the article view:

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

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

by default, this comment will go to the createaction of CommentsController, which you will then probably want to put redirect :backinto so you're routed back to the Articlepage.

默认情况下,此评论将转到 的create操作CommentsController,然后您可能希望将其redirect :back放入,以便您返回到Article页面。