3

我希望有人可以帮助指导我以最好的方式做到这一点。我正在为人们设置一个注册表单,以列出他们在各种工作中的技能/证书

Schema 使用 Mongoid 和 Inheritance 遵循这些思路

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/persons/new,其中将有一个表单来选择各种工作(按各个行业列出和分组:金融、工程、营销),并根据用户的选择,更多详细视图将显示特定于该工作职能。(例如,软件开发人员可以列出编程语言,而会计师可以列出他们是否有注册会计师)。

我的问题是,在控制器和视图层中处理这个问题的最佳方法是什么?我要涵盖大约 100 种不同的工作职能,所以我想将控制器和视图结合起来,而不是将用户重定向到 mysite.com/accountants/new 或 mysite.com/engineers/new 并为每个用户提供一个控制器/视图具体工作。

有人可以帮助指导我解决这个问题的最佳方法吗?我知道我将不得不使用 jQuery 和一些 ajax 调用来呈现详细的表单,但是我应该如何处理控制器,因为 form_for 最初与用户绑定,并且模型的属性有限,所以我不知道如何获取参数并将它们传递到参数哈希中,并对更具体的工作进行验证

4

1 回答 1

2

我最近遇到了这样的问题。我最终使用 form_for 在基本类型上设置了我的表单,在你的情况下是 Person 。在表单中,我为基本字段和单独的字段集标签创建了一个字段集,以表示每个子类中可用的额外字段,如下所示:

<%= 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 在控制器中提供您的“create”方法,其参数如下:

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

在您的表单中,您还需要某种方式来指定工作类型。就我而言,我使用了一个简单的选择标签:

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

这将在您的控制器中为您提供 params[:job_type]。从那里,“创建”方法需要确定用户选择的作业类型,然后创建正确的子类并使用提供的参数。我为此使用了一个案例陈述:

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”的字段集。如果您需要此示例代码,请告诉我。

作为画龙点睛的一笔,您可能会考虑以部分形式呈现特定于作业的字段集,以便您的主窗体只有一系列调用来呈现所有不同类型的作业。

我不知道是否有更好的方法来做到这一点,但这种方法对我来说非常有用,并且允许我拥有一个控制器和一组视图来管理整个父/子子类树的创建和编辑。

于 2012-05-17T22:08:00.957 回答