尝试使用accepts_nested_attributes_for和has_and_belongs_to_many,但未填充连接表

我正在学习RoR并尝试使用accepts_nested_attributes_for和has_and_belongs_to_many来提交传统上是两种forms的信息。 我在一些网站上看到它们兼容,有些网站不兼容,有些网站不知道。 作为参考,我使用的是Rails 2.3.4。 我尝试使用嵌套模型上的Ryan’s Scraps教程对我的解决方案进行建模

从我试图调试,似乎我有两个问题,但我不知道为什么。

  1. 当我提交带有嵌套模型的表单时,只会发布部分嵌套模型信息。 我只得到第一个字段,而不是用户可能选择的“n”个字段
  2. 在发布的单个字段中,没有为我为HABTM关系创建的连接表中插入任何行。

这是我的插入尝试的一段代码和相应的日志:

律师模型:

class Attorney  proc { |a| a['name'].blank? } end 

协会模型:

 class Association  "Please enter an association name." end 

律师控制员:

 def new @attorney = Attorney.new @attorney.associations.build respond_to do |format| format.html # new.html.erb format.xml { render :xml => @attorney } end end def create @attorney = Attorney.new(params[:attorney]) respond_to do |format| if @attorney.save flash[:notice] = 'Attorney was successfully created.' format.html { redirect_to(@attorney) } format.xml { render :xml => @attorney, :status => :created, :location => @attorney } else format.html { render :action => "new" } format.xml { render :xml => @attorney.errors, :status => :unprocessable_entity } end end end 

律师的新观点:

  {:multipart => true}) do |f| %>   


70, :rows => 20 %>


'shared/membership' %>

会员资格部分:

 
true) %>

律师帮助链接:

 def add_association_link(name) link_to_function name do |page| page.insert_html :bottom, :associations, :partial => 'shared/membership', :object => AssociationsAttorneys.new end end 

加入表迁移:

 class CreateAssociationsAttorneys  false t.references :association, :null => false t.timestamps end end def self.down drop_table :associations_attorneys end end 

日志捕获:

  Processing AttorneysController#new (for 127.0.0.1 at 2009-12-04 08:16:19) [GET] Rendering template within layouts/default Rendering attorneys/new [4;35;1mMemberType Load (0.4ms)[0m [0mSELECT * FROM "member_types" [0m [4;36;1mOfficeLocation Load (18.6ms)[0m [0;1mSELECT * FROM "office_locations" [0m [4;35;1mAssociation Load (0.6ms)[0m [0mSELECT * FROM "associations" [0m Rendered shared/_membership (3.5ms) [4;36;1mCACHE (0.0ms)[0m [0;1mSELECT * FROM "associations" [0m Rendered shared/_membership (1.5ms) Rendered shared/_nav (0.6ms) Rendered shared/_footer (0.1ms) Completed in 149ms (View: 114, DB: 20) | 200 OK [http://localhost/attorneys/new] Processing ApplicationController#index (for 127.0.0.1 at 2009-12-04 08:16:19) [GET] Processing AttorneysController#create (for 127.0.0.1 at 2009-12-04 08:16:57) [POST] Parameters: {"commit"=>"Create", "authenticity_token"=>"Jh7aMCcOY7jUu/D1YtiCswg2n6iwqnS98VnVn46psp0=", "associations"=>{"association_id"=>"3"}, "attorney"=>{"birthstate"=>"Alabama", "office_location_id"=>"1", "birthdate"=>"December 3, 2009", "birthcity"=>"Test", "middlename"=>"Test", "lastname"=>"Testing", "image_temp"=>"", "member_type_id"=>"2", "firstname"=>"Test", "bio"=>"testing testing testing", "suffix"=>"", "email"=>"testing@test.com"}} [4;35;1mAttorney Load (15.6ms)[0m [0mSELECT "attorneys".id FROM "attorneys" WHERE ("attorneys"."email" = 'testing@test.com') LIMIT 1[0m [4;36;1mAttorney Create (0.8ms)[0m [0;1mINSERT INTO "attorneys" ("birthstate", "created_at", "birthdate", "office_location_id", "birthcity", "updated_at", "middlename", "lastname", "firstname", "member_type_id", "suffix", "bio", "image", "email") VALUES('Alabama', '2009-12-04 15:16:57', 'December 3, 2009', 1, 'Test', '2009-12-04 15:16:57', 'Test', 'Testing', 'Test', 2, '', 'testing testing testing', NULL, 'testing@test.com')[0m Redirected to http://localhost:3000/attorneys/11 Completed in 150ms (DB: 16) | 302 Found [http://localhost/attorneys] 

我可以看到关联“=> {”association_id“=>”3“}它只获得了我对特定人员的多个关联中的最后一个,并且它没有在连接表中创建任何条目。我的代码出了问题?

你们两个在这里有问题,不幸的是其中一个被另一个掩盖了。

这两个问题源于这一部分观点:

 
<% fields_for :associations do |assoc_form| %> <%= assoc_form.collection_select(:association_id, Association.find(:all), :id, :name, :include_blank => true) %>

问题1:你误解了accept_nested_fields_for的作用。

accepts_nested_fields_for用于创建和修改表单中的相关对象。 它可以用来填充连接表,这是你想要做的事情。 但是,使用accepts_nested_fields_for填充连接表是不可能的HABTM关系。 如果你想创建一个与新律师联系的新协会,那么好好利用accepts_nested_fields_for。 或者,如果您有一个富连接模型,需要每个记录的附加信息。

问题2:您没有将此表单中的字段链接到律师表格。 哪个是必须使用accepts_nested_fields_for。

我们已经确定accepted_nested_fields_for不是你需要完成的,但是,你仍然没有将select association_id字段与表单相关联。 这就是为什么params [associations] [association_id]被设置而不是params [attorney] [association] [association_id]。

问题3:表单结构完全错误,因为它看起来像你想要完成的。

有太多需要纠正我给予适当的分解。 你最好检查复杂表单示例存储库 。 这是accepts_nested_attributes_for的一个工作示例,它不处理任何HABTM关系,但它应该教你需要知道的每件事。 以下更正后的代码是您所需要的90%。 上面链接的复杂表单示例将教您填写add_association_link和create_association_link空白时需要了解的内容。

更正涉及以下步骤:

  1. 创建连接模型,并将关系更改为a到多个,接受连接模型上的嵌套属性。
  2. 在构建物体方面对控制器进行微调。
  3. 将表单构建器对象传递给partial。
  4. 重写部分中的表单,以便重点关注新创建的连接模型。

您可以通过以下更改来完成此操作。

 class Attorney < ActiveRecord::Base has_many :attorney_associations has_many :associations, :through => :attorney_associations accepts_nested_attributes_for :attorney_associations, :reject_if => proc { |a| a['association_id'].blank? } accepts_nested_attributes_for :associations, :reject_if => proc {|a| a['name'].blank?} end class AttorneyAssociations < ActiveRecord::Base belongs_to :attorney belongs_to :association end 

律师控制员:

 def new @attorney = Attorney.new @attorney.associations.build @attorney.attorney_associations.build respond_to do |format| format.html # new.html.erb format.xml { render :xml => @attorney } end end 

新律师查看:

 <% form_for(@attorney, :html => {:multipart => true}) do |f| %> <%= f.error_messages %> <%= f.label :"First name" %> <%= f.text_field :firstname %>
<%= f.label :"Last Name" %> <%= f.text_field :lastname %>
<%= f.label :"Attorney Type" %> <%= f.collection_select :member_type_id, MemberType.all, :id, :name %>
<%= f.text_area :bio, :cols => 70, :rows => 20 %>

<%= f.label :"Attorney Location" %> <%= f.collection_select :office_location_id, OfficeLocation.all, :id, :location %>
<% f.fields_for :attorney_association do |aa_form| %> <%= render :partial => 'attorney_association', :locals => {:f => aa_form} %> <% end %> <%= add_association_link "Add Another Existing Association" %> <% f.fields_for :associations do |assoc_form| %> <%= render :partial => 'attorney', :locals => {:f => assoc_form} %> <%= create_association_link, "Create a New Association for this Attorney" %>
<%= f.submit 'Create' %> <% end %>

我假设add_association_link是一个javascript帮助器,它创建一个链接来克隆一个什么是Membership partial的空实例。 create_association_link是类似帮助器的占位符,它将为新关联添加部分。

律师协会部分:

  
<%= f.collection_select(:association_id, Association.find(:all), :id, :name, :include_blank => true) %> <%= link_to_function "remove", "$(this).up('.attorney_association').remove()" %>

协会部分:

  
<%= f.label_for :name %> <%= f.text_field :name %> <%= link_to_function "remove", "$(this).up('.attorney_association').remove()" %>