如何在rails中构建复杂的表单,允许我关联或创建新的相关实体?

关于rails复杂forms的stackoverflow有很多问题,它们似乎都指向了Ryan Bates关于这个主题的漂亮的railscast演示: part1和part2 。

这对它的作用很有帮助,但我没有看到解决您可能想要创建新子对象的情况的问题,或者您可能想要关联已存在的对象。

在我的情况下,我希望用户能够创建一个新的事件。 作为其中的一部分,他们需要说明谁参与了事件。 大约一半的时间,添加到事件中的人员已经存在于数据库中。 在这种情况下,应鼓励用户使用这些现有记录而不是创建新记录。

关于如何在表单中处理这种复杂性的任何建议?

作为解决方案的一部分,您是否建议,如果用户未找到应用程序继续执行的人并在提交父对象之前动态创建它? 我的想法(但有兴趣听取建议)是用户应该使用现有的Person记录(如果有),但是如果用户需要创建一个新的Person记录,则该新记录不会提交给DB,直到用户提交事件。 思考?

嗨,要完成你需要做的事,有几个简单的步骤要遵循:1)在模型类(在你的情况下的事件和人类)确保你这样的东西:

class Incident < ActiveRecord::Base has_and_belongs_to_many :people # Note if you want to be able to remove a person from the Incident form (to de-associate) put true in :allow_destroy => true on the accepts_nested_attributes_for accepts_nested_attributes_for :people, :allow_destroy => false, :reject_if => :all_blank validates_associated :people #so you won't be able to save invalid people objects attr_accessible :date_occur, :location, :people_attributes # note the :people_attributes here #do your Incident validations as usual... end class Person < ActiveRecord::Base has_and_belongs_to_many :incidents #the following line it's to allow mass assignment, basically it will allow you to create people from the Incident form attr_accessible :first_name, :last_name, :dob #do your Person validations as usual... end 

2)在视图方面,最简单的方法是修改事件表单文件(app / view / incidents / _form.html.erb),以允许用户为事件分配现有人员和创建新人员:

 # app/view/incidents/_form.html.erb <%= semantic_form_for(@incident) do |f| %> <% if @incident.errors.any? %> 

<%= pluralize(@incident.errors.count, "error") %> prohibited this incident from being saved:

    <% @incident.errors.full_messages.each do |msg| %>
  • <%= msg %>
  • <% end %>
<% end %>
<%= f.label :date_occur %>
<%= f.datetime_select :date_occur %>
<%= f.label :location %>
<%= f.text_field :location %>
<%= f.input :people, :as => :select, :collection=>Hash[Person.all.map { |p| [p.first_name + ' - ' + p.last_name, p.id] }] %> <%= f.fields_for :people, Person.new() do |new_person_form| %>
<%= new_person_form.inputs :name=>'Add New person' do %> <%= new_person_form.input :first_name, :label=>'First Name: ' %> <%= new_person_form.input :last_name, :label=>'Last Name: ' %> <%= new_person_form.input :dob, :label=>'Date of birth: ' %> <% end %>
<% end %>
<%= f.submit %>
<% end %>

3)最后,您需要修改更新并为事件控制器创建方法,如下所示:

 # app/controllers/incident_controller.rb def create selected_people = params[:incident][:person_ids].keep_if{ |v| v.present? } params[:incident].delete(:person_ids) @incident = Incident.new(params[:incident]) @incident.people = Person.find( selected_people ) respond_to do |format| if @incident.save format.html { redirect_to @incident, notice: 'Incident was successfully created.' } format.json { render json: @incident, status: :created, location: @incident } else format.html { render action: "new" } format.json { render json: @incident.errors, status: :unprocessable_entity } end end end def update selected_people = params[:incident][:person_ids].keep_if{ |v| v.present? } params[:incident].delete(:person_ids) @incident = Incident.find(params[:id]) @incident.people = Person.find( selected_people ) respond_to do |format| if @incident.update_attributes(params[:incident]) format.html { redirect_to @incident, notice: 'Incident was successfully updated.' } format.json { head :no_content } else format.html { render action: "edit" } format.json { render json: @incident.errors, status: :unprocessable_entity } end end end 

就是这样,如果您需要进一步的帮助,请告诉我。 联邦快递