2010-11-06 77 views
1

嘿傢伙,我無法理解Rails構造。我正在使用Rails 3,但我懷疑這是特定於此版本的。Rails模型 - 關聯表格問題

我有一個模型,Goalhas_many :commits和自然,Commit模型belongs_to :goal。我創建了適當的遷移,以便commits_table.references :goal

我實際上是通過Rails Getting Started指南,除了那篇文章中他們分別使用PostComment

現在我已經描述了情況,我可以表達我的困惑。在Goal顯示視圖中,我嵌入了一個表單來創建一個新的提交,它與當前查看的目標「附加」。這工作正常,所有。然而,我無法理解爲什麼我們做這個

<%= form_for([@goal, @goal.commits.build]) do |f| %> 

不是應該form_for(@commit)?我明白爲什麼我們想要@goal提供一些上下文,因爲提交是一個嵌套的資源。但是,在實際生成的源中,表單被合適地命名爲commit,即字段名爲commit_blah。 Rails如何知道這一點?我知道有這整個系統的「信任和魔力」等等,但我的意思是至少在高層次上,從代碼暗示的Rails中我想要一個提交?

我看着documentation for form_for它似乎是其中一個參數可能是採取的形式的行動。我想在這種情況下,這就是@goal.commits.build參數的用途?指定要採取的行動?這是Rails如何推斷我想要提交?這也能解釋爲什麼這個表格是由Commit控制器處理的,即使這個代碼是在目標的視圖中?

此外,爲什麼這些參數作爲數組傳遞([])?在Ruby中,該方法仍然只是將它作爲兩個單獨的參數,或者有這個原因通過這種方式的原因嗎?

最後,rails generate自動給我在我的其他_form.html.erb諧音一些錯誤顯示代碼:

<% if @commit.errors.any? %> 
    <div id="error_explanation"> 
    <h2><%= pluralize(@commit.errors.count, "error") %> prohibited this commit from being saved:</h2> 

    <ul> 
    <% @commit.errors.full_messages.each do |msg| %> 
     <li><%= msg %></li> 
    <% end %> 
    </ul> 
    </div> 
<% end %> 

如果我想要將它添加到這個嵌入式的形式,我會怎麼做呢?我想我的問題是,我會用什麼來代替@commit

謝謝。我只是試圖讓我的頭腦圍繞這些新概念。

+1

關於你在form_for([@ goal,@ goal.commits.build])中@goal的目的問題''。在Rails代碼中很難看到,但是該數組傳遞給了其他各種Rails方法。最終,Rails將使用該數組的信息爲您創建一個嵌套路由('/ goals/1/commits/new')。從'form_for'代碼,你必須查看#apply_form_for_options!(record_or_name_or_array,options) - > #polymorphic_path() - > #polymorphic_url - > #build_named_route_call的代碼。 – monocle 2010-11-06 22:53:07

+0

所以我猜'慣例'是傳遞'上下文',可以這麼說,以便它可以構建嵌套的資源。 '約定'也是讓數組的最後一個元素成爲我們實際想要構建的元素。非常感謝! – 2010-11-06 23:00:45

回答

1

如果你回到文檔,然後單擊「顯示源代碼」,你會看到

def form_for(record_or_name_or_array, *args, &proc) 
    ... 
    case record_or_name_or_array 
    when String, Symbol 
    ... 
    when Array 
    object = record_or_name_or_array.last 
    object_name = options[:as] || ActiveModel::Naming.singular(object) 
    apply_form_for_options!(record_or_name_or_array, options) 
    args.unshift object 
    else 
    ... 
    end 
    ... 
    output << fields_for(object_name, *(args << options), &proc) 
    ... 

對於的form_for,第一個參數可以是一個記錄,名稱或數組。在你的情況下,你傳遞一個數組。然後代碼將「對象」確定爲該數組的最後一個成員,即您的@ goal.commits.build對象。對象名稱由ActiveModel::Naming.singular方法確定。

console > ActiveModel::Naming.singular(@goal.commits.build) 
=> "commit" 

然後它使用fields_for和'commit'生成適當的表單字段。

+0

謝謝單片眼鏡。還有一個問題,如果form_for的結果是@ goal.commits.build,那麼在數組中傳遞@goal有什麼意義?我檢查了來源,但沒有看到任何相關的。 – 2010-11-06 22:12:19

0

看起來您正在使用嵌套資源。請檢查您的routes.rb文件,看看是否有你喜歡的東西:

map.resources:承諾,:的has_many =>:目標

或者是:

map.resources:承諾做|提交| commit.resources:goals end

如果是這種情況,那麼您需要將提交和目標對象都提供給form_for方法。

+0

謝謝。如果你閱讀我的問題,我確實說明我正在使用嵌套資源。事實上,我不知道你是否知道我甚至在問什麼。一切工作都很好,只是我不明白爲什麼有必要這樣做。 – 2010-11-06 00:47:07

+0

我看過你的電子郵件,但我想我誤解了你的問題。但是,正如我所提到的,您必須提供兩者,因爲它是嵌套資源,不知道哪個提交擁有目標,就無法創建有效的URL。例如。路徑應該是/ commit /:id/goals /:id之類的東西,它不能在不知道提交和目標的情況下創建它。 – anotherdjohnson 2010-11-06 01:48:32