ruby-on-rails - 基于用户输入的动态表单和模型创建

标签 ruby-on-rails ruby-on-rails-3 forms model-view-controller mongoid

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

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

我的问题是,在 Controller 和 View 层中处理此问题的最佳方法是什么?我涵盖了大约 100 种不同的工作职能,所以我想结合 Controller 和 View ,而不是将用户重定向到 mysite.com/accountants/new 或 mysite.com/engineers/new 并为每个都有一个 Controller / View 具体工作。

有人可以帮助指导我解决这个问题的最佳方法吗?我知道我将不得不使用 jQuery,也许还有一些 ajax 调用来呈现详细的表单,但是我该如何处理 Controller ,因为 form_for 首先与用户相关联并且那里的模型具有有限的属性,所以我不确定如何获取参数并将它们传递到参数散列中,并验证更具体的作业

最佳答案

我最近遇到了这样的问题。我最终在基本类型上使用 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 在 Controller 中提供您的“创建”方法,参数如下:

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

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

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

这将在您的 Controller 中为您提供 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”的字段集。如果您需要示例代码,请告诉我。

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

我不知道是否有更好的方法来做到这一点,但这种方法对我来说非常有效,它允许我有一个 Controller 和一组 View 来管理整个父/子子类的创建和编辑树。

关于ruby-on-rails - 基于用户输入的动态表单和模型创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10637172/

相关文章:

ruby-on-rails - 在没有 accepts_nested_attributes_for 的情况下处理 Rails 中的嵌套 JSON

javascript - 表单提交不适用于validationSchema

ruby-on-rails - 对哈希数组中的值求和的更好方法

ruby-on-rails - 在rspec中使用ActiveJob执行挂起的作业

ruby-on-rails-3 - 嵌套:json包含在Rails中

forms - 为什么我的选择字段仍然是必需的?

php - 简单的ajax表单提交报错

ruby-on-rails - 如何使 cancan 授权 gem 将用户限制为他们拥有的数据?

ruby-on-rails - rails : Share variables between controller and view

ruby-on-rails - 如何在 Rails 中的 Web 请求中对长进程进行子线程化