3

我希望有人能幫助指導我做到這一點的最佳方式。我設立一個註冊表單的人列出他們的技能/證書在各個工作崗位基於用戶輸入的動態表單和模型創建

架構是沿着使用Mongoid和繼承

這些線路
class Person 
    include Mongoid::Document 
    field :name, :type => String 
    field :education, :type => String 
end 

class Accountant < Person 
    field :cpa, :type => Boolean 
    field :active_cpa, :type => Boolean 
end 

class SoftwareDeveloper < Person 
    field :full_stack, :type => Boolean 
    field :language, :type => Array 
end 

因此,用戶會來一個註冊網頁的mysite .com /個人/新會有一種表格可以選擇各種工作(按各行業列出和分組:財務,工程,市場營銷),並根據用戶的選擇,更詳細的視圖將顯示特定於該工作職能。 (例如軟件開發人員可以列出編程語言,會計師可以列出他們是否擁有CPA)。

我的問題是,在控制器和視圖層處理這個問題的最好方法是什麼?有大約100個不同的工作職能我所覆蓋,所以我想結合控制器和視圖,而不是將用戶重定向到mysite.com/accountants/new或mysite.com/engineers/new併爲每個控制器/視圖具體的工作。

有人可以請幫助指導我解決這個問題的最佳方法嗎?我知道我將不得不使用jQuery,也許一些ajax調用來渲染詳細的表單,但是我怎麼處理控制器,因爲form_for最初與用戶綁定在一起,並且模型的屬性有限,所以我不知道如何獲取參數並將它們傳遞到參數hash中,以進行更具體的作業驗證

回答

2

我最近遇到了類似這樣的問題。我最終在基礎類型Person上使用form_for設置了我的表單。在表格中,我創建的基礎領域和獨立的字段集標記一個字段來表示每個子類中可用的額外字段,像這樣:

<%= form_for @person do |f| %> 

<fieldset id="base"> 
    <%= f.label :name %> 
    <%= f.check_box :name %> 
    <!-- ... --> 
</fieldset> 

<fieldset id="accountant"> 
    <%= fields_for :accountant do |f| %> 
    <%= f.label :cpa %> 
    <%= f.check_box :cpa %> 
    <!-- ... --> 
    <% end %> 
</fieldset> 

<fieldset id="software_developer"> 
    <%= fields_for :software_developer do |f| %> 
    <%= f.label :full_stack %> 
    <%= f.check_box :full_stack %> 
    <!-- ... --> 
    <% end %> 
</fieldset> 

這種使用fields_for將導致表單POST提供您的「創造」法在控制器與像PARAMS:

params[:person] = { :name => "Joe Smith", ... } 
params[:accountant] = { :cpa => true, ... } 
params[:software_developer] = { :full_stack => false, ... } 

在你的方式,你會希望有指定作業類型的一些方法。就我而言,我用一個簡單的選擇標籤:

<%= select_tag :job_type, options_for_select(@job_types) %> 

這將爲您提供使用參數[:工作類型]在您的控制器。從那裏,「創建」方法需要找出用戶選擇哪種工作類型,然後創建正確的子類並使用提供的參數。我爲此使用了一個案例聲明:

case params[:job_type] 
when :accountant 
    @person = Accountant.new(params[:person].merge(params[:accountant])) 
when :software_developer 
    @person = SoftwareDeveloper.new(params[:person].merge(params[:software_developer])) 
when ... 
end 

如果您有很多子類,那可能不是非常可擴展的。所以你可以做的是安排params [:job_type]給你創建類的名字作爲表單提交的值。然後你可以這樣做:

@person = params[:job_type].constantize.new(params[:person].merge(params[params[:job_type].underscore]) 

此代碼使用作業類型字段轉換爲類名稱,然後再次爲子類查找正確的字段。

最後,當用戶選擇不同的作業類型時,您需要使用一些jQuery來隱藏和顯示不同的字段集。爲此,將.change()處理程序附加到select_tag元素,並使其隱藏所有字段集,然後使用與所選作業類型匹配的「id」顯示一個字段集。讓我知道你是否需要這樣的示例代碼。

作爲一種畫龍點睛的表情,您可能會考慮在部分渲染中渲染特定於工作的字段集,以便您的主窗體只需調用一系列渲染所有不同類型的作業。

我不知道是否有更好的方法來做到這一點,但這種方法對我來說真的很棒,並允許我有一個控制器和一組視圖來管理整個父母/孩子的創建和編輯子類樹。

+0

感謝您的支持。這非常有幫助。我正在花這個週末試圖在我的代碼中實現這一點。你可能會給我一個你提到的.change()方法的例子嗎?我不確定是否應該爲每個job_type加載所有不同的字段集,或者只是基於所選的job_type添加特定字段。無論如何,感謝您的幫助! –

+0

是的,我可以用示例更改方法更新答案。你可以在.change方法中做的一件事就是從服務器動態加載所選作業類型的字段集。有人主張使用JSON來做AJAX,有時候也沒關係。但在這種情況下,您希望您的表單片段已準備好從服務器加載格式化。這樣你就可以在ERB的服務器端完成你所有的佈局,或者你不需要在JavaScript中創建來自JSON等的表單字段。 – OzBandit

+0

你可能想檢查'params [:job_type]'是在將它傳遞給'.constantize.new'以避免任意代碼執行之前,它是一個授權值。 – ybart

相關問題