2010-01-09 244 views
106

我有一個關於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爲零,這會錯誤地等。」我也試着

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

哪個正確呈現,但涉及f.text_area文章的「文本」字段,而不是評論的,​​並提出了在該文本區域article.text屬性的HTML。所以我似乎也有這個錯誤。我想要的是一個表單,其'submit'將在CommentsController上調用create操作,在params中帶有article_id,例如對/ articles/1/comments的發佈請求。

我的問題的第二部分是,創建評論實例的最佳方式是什麼?我在ArticlesController的show動作中創建了@comment,所以一個註釋對象將在form_for助手的範圍內。然後在CommentsController的創建動作中,我使用從form_for傳入的參數創建新的@comment。

謝謝!

回答

207

特拉維斯R是正確的。 (我希望我可以upvote你。)我剛剛得到這個工作自己。有了這些路線:在

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

發送到控制器

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

只是因爲它說在http://guides.rubyonrails.org/routing.html#nested-resources,沒有特殊的命名空間:

resources :articles do 
    resources :comments 
end 

你得到這樣的路徑。

但部分和形式變得棘手。請注意括號:

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

最重要的是,如果你想有一個URI,你可能需要的東西是這樣的:作爲http://edgeguides.rubyonrails.org/routing.html#creating-paths-and-urls-from-objects

描述

[@article, @comment] 

article_comment_path(@article, @comment) 

或者

例如,在與comment_item suppli編輯迭代,

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

jamuraa說什麼可以在文章的背景下工作,但它不適用於我以其他各種方式。

有很多關於嵌套資源的討論,例如, http://weblog.jamisbuck.org/2007/2/5/nesting-resources

有趣的是,我剛剛瞭解到大多數人的單元測試實際上並沒有測試所有路徑。當人們遵循jamisbuck的建議時,他們最終有兩種方法來獲取嵌套資源。他們的單元測試通常將GET/POST到最簡單的:

# 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 

對不起,長答案。我想,沒有多少人知道這些微妙之處。

+0

這是工作,但我必須像jamuraa說的那樣修改控制器。 – 2014-05-17 15:26:27

+0

果醬的方式很有效,但您最終可能會遇到您可能不知道的其他路線。最好是明確的。 – cdunn2001 2014-06-28 19:13:32

+0

我嵌套了資源,@result在@course裏面。儘管'[@result,@ course]'有效,但'form_for(@result,url:{action:「create」})'也可以。這隻需要最後的型號名稱和方法名稱。 – Anwar 2015-09-04 05:57:54

33

你不需要在表格中做特殊的事情。你只要建立正確的註釋在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頁面。

+9

我不得不使用'form_for([@ article,@new_comment])'格式。我認爲這是因爲我正在顯示'comments#new'的視圖,而不是'article#new_comment'。我在'article#new_comment'中找到了Rails是否足夠聰明,可以計算出註釋對象所嵌入的內容,並且您不必指定它? – Soup 2012-05-05 08:28:23

51

一定要在控制器中創建兩個對象:@post@comment的職位名稱,例如:

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

然後在視圖:

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

一定要在明確定義數組form_for,而不僅僅是像上面那樣逗號分開。

+0

Travis's是一箇舊的答案,但我相信它是最正確的Rails 3.2.X.如果您希望表單構建器的所有元素都填充「註釋」字段,則只需使用數組,則不需要url幫助器。 – Karl 2013-04-17 04:05:48

+1

只設置操作嵌套的父對象。如果你只是部分嵌套資源(例如按照例子),那麼設置父對象將導致form_for失敗(剛剛用rails 5.1重新確認) – iheggie 2017-07-23 19:44:37