表单中的嵌套关​​联未正确更新

时间:2014-10-13 22:36:43

标签: ruby-on-rails

我有以下情况。联系人has_many lead_profiles。我有一个新的lead_profile表单,用户输入有关lead_profile和联系人的信息。但是,我使用的是jquery自动填充插件,如果联系人已经存在,用户可以选择它,然后创建一个隐藏的输入id属性,表明它不再是新的联系人:

  # controller
  def new
    @lead_profile = LeadProfile.new
    @contact = @lead_profile.build_contact name: "Donato"
  end

  # view
  <%= form_for @lead_profile do |f| %>
    <%= f.fields_for :contact do |builder| %>
      <%= builder.text_field :name %>
      <%= builder.text_field :address %>
    <% end %>    
  <% end %> 

  # javascript
  $('#lead_profile_contact_attributes_address').bind('typeahead:selected', function(obj, datum, name) {  
    var $parent = $("#lead_profile_contact_attributes_address").closest(".form-group");
    $parent.after('<input name="lead_profile[contact_attributes][id]" type="hidden" value="' + contact.id + '">')
  });

现在,当表单提交给创建时,我需要确定联系人是否存在。请注意,如果我没有这样做,并且发送了一个id属性以便联系回服务器,Rails会引发一个异常&#34;找不到ID = 10的联系人,其中ID =&#34的LeadProfile ;。所以我必须覆盖contact_attributes = call:

  def contact_attributes=(params)
    if params[:id].present?
      self.contact = Contact.find(params[:id])
    else
      self.contact = Contact.new params
    end
  end

上面,我确定联系人是新联系人还是现有联系人(如果用户从javascript自动填充中填充联系人,则会出现这种情况)。

一切似乎都很好。如果联系人是新的,则在数据库中使用params hash的属性创建新联系人。如果联系人存在,则使用表单中的属性更新现有联系人。在这两种情况下,lead_profiles记录都与该联系人相关联。

但是现在当我想要更新lead_profile时会出现问题。我使用相同的表单进行更新,就像我对新的一样:

 <%= form_for @lead_profile do |f| %>
    <%= f.fields_for :contact do |builder| %>
      <%= builder.text_field :name %>
      <%= builder.text_field :address %>
    <% end %>    
  <% end %>  

如果我更新了lead_profile表单中的联系信息,则联系人不会在数据库中更新,因为我需要这种覆盖:

  def contact_attributes=(params)
    if params[:id].present?
      self.contact = Contact.find(params[:id])
    else
      self.contact = Contact.new params
    end
  end

如果我将其删除,那么联系人将会更新,但是在创建新联系人时我会遇到另一个问题:

Couldn't find Contact with ID=10 for LeadProfile with ID=   

我真的想以单一形式将这两个模型保存在一起,Rails不应该限制我。我现在该怎么办?

2 个答案:

答案 0 :(得分:0)

好的,我有一个解决方案正常工作。请记住,当您对模型进行更新时,只要在模型上调用save,它就会自动对关联进行更新。默认情况下,它将根据fields_for嵌套表单中的输入更新其关联属性。但是,只要覆盖该默认值并调用find,显然关联时不会更新任何内容:

def contact_attributes=(params)
    if params[:id].present?
      self.contact = Contact.find(params[:id])
    else
      self.contact = Contact.new params
    end
  end

解决方案是以某种方式区分您何时更新模型以及何时通过自动完成通过表单动态构建现有模型关联。我为此目的使用了虚拟属性。如果该字段是由自动完成动态生成的,则这不是rails默认值,您必须自己处理它:

  model Contact < ActiveRecord::Base
    attr_accessor :autocompleted
  end

  model LeadProfile < ActiveRecord::Base
      def contact_attributes=(params)
        # this contact model was autocompleted via javascript
        if params[:id].present? && params[:autocompleted].present?
        self.contact = Contact.find(params[:id])
      else
        # self.contact = Contact.new params
        super
      end
    end

在所有其他情况下,调用super并让Rails执行其默认行为。

答案 1 :(得分:0)

只是猜测尝试在您的fields_for中添加联系人实例,即

<%= f.fields_for :contact,@contact do |builder| %>
  <%= builder.text_field :name %>
  <%= builder.text_field :address %>
<% end %>

如果有效,请告诉我。我经常遇到嵌套表单的随机问题,有时显式设置嵌套表单的目标对象可以解决问题