我有两个模型:公司和人
class Person < ActiveRecord::Base
belongs_to :company
end
class Company < ActiveRecord::Base
has_many :people
accepts_nested_attributes_for :people, :allow_destroy => true, :reject_if => proc {|attrs| attrs.all? {|k,v| v.blank? } }
end
我的HTML表单部分用于新建和编辑操作,如下所示:
<% form_for(@company) do |company_f| %>
<p>
<b>Name</b><br />
<%= company_f.text_field :name %>
</p>
<ul>
<%= render :partial => 'person_fields', :collection => @company.people, :locals => {:company_f => company_f} %>
<%= link_to_add_fields(:people, company_f) %>
</ul>
<p>
<%= company_f.submit "Submit" %>
</p>
<% end %>
其中“_person_fields”部分看起来像这样:
<li>
<% company_f.fields_for :people, person_fields do |person_f| %>
<%= person_f.label :name %>
<%= person_f.text_field :name %>
<% end %>
</li>
目前,如果我输入person_f.text_fiel:输入此人的姓名,然后点击“保存”,则会创建一个具有该名称的新Person模型。不是我想要的,我已经在数据库中拥有那个人的Person模型,我宁愿将这个人与这家公司联系起来。
另一件事是,我不介意使用该名称进行人性化识别,而不是像“_person_fields”部分这样的id
<li>
<% company_f.fields_for :people, person_fields do |person_f| %>
<%= person_f.label :id %>
<%= person_f.text_field :id %>
<% end %>
</li>
顺便说一句,这也不起作用。当我点击提交时,没有任何反应。什么都得不到保存或改变或任何东西
所以我想,仅仅是为了实验,我说我确实使用id来识别Person模型,(因此我不需要使用隐藏的id字段进行自动完成,我将其用于另一个项目。我讨厌它)。我想要的只是:转到一个新的/编辑公司页面,有一堆文本字段供我输入人员ID,然后保存,然后这些人与公司联系。我的意思是,它就像
people = Person.find(1,2,3)
#=>["romeo","juliet","henry"]
company = Company.first
#=>["Shakespeare Co."]
company.people<<people
company.people
#=>["romeo","juliet","henry"]
如果我不必使用选择菜单,那将是最好的,因为最终如果项目起飞并且我有一千人,那对于任何选择菜单来说都太大了。我知道然后我将不得不使用autocomplete + hidden id字段,当选择一个人的名字时,它会被设置。
谢谢!
答案 0 :(得分:4)
accepts_nested_attributes_for :people
定义了公司模型中的people_attributes
和people_attributes=
方法。当您在表单中fields_for :people
时,将使用这两种方法。如documentation中所述(阅读整页,不仅仅是方法定义):
嵌套属性允许您通过父级保存关联记录的属性。
关联两个对象不起作用,没有它就可以完成,你在公司中仍然有people
方法。
Formtastic例如使用具有多个属性的select(您可以使用ctrl检查多个选项)或check_boxes列表(对普通用户更容易,不必触摸键盘)。
如果你想使用自动完成功能,可以这样做,但是你需要将你的id附加到people[]
数组(现在不记得格式了,稍后我会检查。你可以检查它的格式您在表单中为:people
创建属性我认为
编辑:
我认为我知道这很简单(没有自动完成,只有简单的html)。
在companies/edit
(或new
)观看位置:
<p>
<%= company_f.label :people %>
<%= company_f.collection_select :person_ids, Person.all, :id, :name, {}, {:multiple => true} %>
</p>
这将允许您选择多个人到公司(使用Ctrl)。此部分生成的参数现在应该转移到您的控制器:
"company"=>{"name"=>"CompanyA", "person_ids"=>["1", "3"]}, "commit"=>"Update", "id"=>"4"
如果你想向人们展示复选框,我设法得到它(我从formtastic复制了部分标记):
<ul>
<% Person.all.each do |person| %>
<li>
<%= check_box :person, :id, {:name => "company[person_ids][]", :checked => @company.people.include?(person) }, person.id, nil %>
<%= person.name %>
</li>
<% end %>
</ul>
我今天没时间检查如何使用隐藏字段进行操作,因此您可以使用自动填充,但我相信它应该与复选框类似 - 您需要使用为每个自动填充添加<input type="hidden" name="company[person_ids][]" value="#{person.id}">
的内容此人,还需要创建已在公司中的人员的初始列表(您覆盖列表,而不是添加到列表中)。
如果您希望字段添加或删除(单独的字段,抱歉)来自公司的人员,那么这应该有效:
公司模式中的:
def add_people=(people_ids)
ids = people_ids.split(/,/).map(&:to_i)
person_ids += ids if ids
end
def add_people
""
end
def remove_people=(people_ids)
ids = people_ids.split(/,/).map(&:to_i)
person_ids -= ids if ids
end
def remove_people
""
end
并在您的新/编辑视图中:
<p>
<%= f.label :add_people %><br />
<%= f.text_field :add_people %>
</p>
<p>
<%= f.label :remove_people %><br />
<%= f.text_field :remove_people %>
</p>
现在你需要做的就是找到自动完成的JavaScript,将它连接到所有人的ID和名称(可能PeopleController#index, :format => :json
应该是好的)并告诉它填充那些text_fields(可以是隐藏字段)如果您使用自动完成功能。)
这种方法应该有效,因为您在公司模型中定义虚拟属性,并通过以"1, 2, 6"
格式为其分配字符串,您可以从关联人员的集合中添加/删除这些ID