2011-12-07 98 views
2

我現在已經被問了上千次,但這並不幫助我嘿:)我一直在這一個小時。我的形式:Rails路由錯誤的嵌套form_for

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

我耙路線:

    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_comments_path ..這是正確的acc奧爾丁的耙路線的..我得到:

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

幫助是非常讚賞..一直在尋找這幾個小時..

UPDATE:

感謝您瑞安這樣一個偉大的答案!一個非常清楚的解釋,我只是在'扔東西',現在至少我理解得更好。實際上,我的耙路線中已經有了'trunk_root_comments_path',並且我嘗試了一些你提到的組合,但是我沒有真正地琢磨我錯過了什麼,所以你的幫助。我使用的是Mongo,實際上我沒有Trunk模型,我只有一個名爲@ root.trunk的屬性,雖然我有一個trunk控制器,因此它是我路線的一部分(也許是一個糟糕的主意idk) 。

所以,我想你的TLDR,它說錯誤:

Undefined method 'root_comments_path' 

..不會造成幹線模型存在,我想..所以我做了@trunk剛好等於正確的ID與

= form_for [@trunk, @root, @comment] do |f| 

< - 和我「未定義的方法`politics_root_comments_path」。我盤算好..這可能是有道理..因爲我失敗,我必須一試你最明確的版本:

= 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是如何工作的,但是需要閱讀更多內容才能真正完成我的想法。我現在也能夠以更長的形式構建適當的路線,至少可以解決這種棘手的情況。所以,謝謝:)

+0

忽略我的答案(至少一段時間:))你的路線如何設置? – jlundqvist

回答

10

TL; DR你需要指定您的網址既是: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;博士

冷卻器方式做到這一點是這樣的:

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將把這個數組的每個元素並建立一個路由幫助器方法名稱由不同部分組成。這不是真正的form_for一部分,但另一種方法叫做url_for,您可以通過單獨使用:

url_for([trunk, root, comment]) 

在開始的時候,通過url_for生成此路由helper方法名稱只是一個空數組([])。沒有什麼特別的。

但是接下來會發生什麼特!

第一個元素將是Trunk類的持久實例。通過「堅持」我的意思是這是一個對象,將直接映射到數據庫中的記錄。 Yay ORMs!

Rails會知道這一點,所以會將路由幫助程序變爲:[:trunk]

第二個元素將是Root類的持久實例。 Rails也知道這一點(該死的,Rails是smart!),然後將它添加到數組中,將它變成[:trunk, :root]。真棒。

然後通過Rails檢查第三個(也是最後一個)元素。它認爲(在這種情況下)它是一個非持久性元素,即它沒有被保存到數據庫中。 Rails的對待這個不同,反而會追加[:comments]到數組,把它變成這樣:

[:trunk, :root, :comments] 

看到我這個現在要去哪裏?

現在Rails已經完成它的東西(或,如果你喜歡),它將這三個部位連接在一起,就像這樣:trunk_root_comments,只是很好的措施它會讓_path在它的結束,轉向它進入最後的trunk_root_comments_path幫手。

然後!男人,然後...... Rails調用這個方法並傳遞它的參數!就像這樣:

trunk_root_comments_path(:trunk_id => trunk.id, :root_id => root_id) 

這產生於資源的完整路徑是這樣的:

/t/:trunk_id/r/:root_id/comments 

而且嘭!整圈!這就是Rails知道如何生成URL並且不必再使用醜陋的哈希。

成功!

+0

在非常好的答案。在這裏閱讀你的動物是非常好的。 – lucapette

+1

謝謝瑞恩!多好的答案。希望更多有路由問題的人看到這一點。得到它的工作,雖然也許不像我想要的tldr,但你可以看到我的更新的細節。謝謝 :) – Inc1982

0

不知道你是否有這條路線設置,但嘗試:

= form_for @comment, :url => trunk_root_comments_path 
+0

無法正常工作,路由需要同時傳遞或傳遞此表單的請求中可用的':trunk_id'和':root_id'參數。 –

+0

哦,我完全錯過了。 – jlundqvist

+0

感謝jlundqvist的迴應。我上面更新了我的答案,以反映我是如何使用Ryan Bigg的建議之一來工作的。 – Inc1982