简体   繁体   English

如何使用accepts_nested_attributes_for?

[英]How do I use accepts_nested_attributes_for?

Editing my question for conciseness and to update what I've done: 为简洁起见,请编辑我的问题并更新我所做的事情:

How do I model having multiple Addresses for a Company and assign a single Address to a Contact, and be able to assign them when creating or editing a Contact? 如何为公司具有多个地址建模,并为联系人分配一个地址,并在创建或编辑联系人时进行分配?

I want to use nested attributes to be able to add an address at the time of creating a new contact. 我想使用嵌套属性来在创建新联系人时添加地址。 That address exists as its own model because I may want the option to drop-down from existing addresses rather than entering from scratch. 该地址作为其自身的模型存在,因为我可能希望该选项从现有地址下拉而不是从头输入。

I can't seem to get it to work. 我似乎无法正常工作。 I get a undefined method `build' for nil:NilClass error 我为nil:NilClass错误得到一个未定义的方法'build'

Here is my model for Contacts: 这是我的通讯录模型:

class Contact < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :title, :phone, :fax, :email, :company, 
                  :date_entered, :campaign_id, :company_name, :address_id, :address_attributes

  belongs_to :company
  belongs_to :address
  accepts_nested_attributes_for :address
end

Here is my model for Address: 这是我的地址模型:

class Address < ActiveRecord::Base
  attr_accessible :street1, :street2, :city, :state, :zip

  has_many :contacts
end

I would like, when creating an new contact, access all the Addresses that belong to the other Contacts that belong to the Company. 我想在创建新联系人时,访问属于公司的其他联系人的所有地址。 So here is how I represent Company: 所以这是我代表公司的方式:

class Company < ActiveRecord::Base
  attr_accessible :name, :phone, :addresses

  has_many :contacts

  has_many :addresses, :through => :contacts

end

Here is how I am trying to create a field in the View for _form for Contact so that, when someone creates a new Contact, they pass the address to the Address model and associate that address to the Contact: 这是我尝试在View for _form for Contact中创建一个字段的方式,以便当某人创建新的Contact时,他们将地址传递给Address模型并将该地址与Contact关联:

  <% f.fields_for :address, @contact.address do |builder| %>
  <p>
    <%= builder.label :street1, "Street 1" %> </br> 
    <%= builder.text_field :street1 %>
  <p>
  <% end %>

When I try to Edit, the field for Street 1 is blank. 当我尝试编辑时,“街道1”的字段为空白。 And I don't know how to display the value from show.html.erb. 而且我不知道如何显示show.html.erb中的值。

At the bottom is my error console -- can't seem to create values in the address table: 最下面是我的错误控制台-似乎无法在地址表中创建值:

My Contacts controller is as follows: 我的联系人控制器如下:

  def new
    @contact = Contact.new
    @contact.address.build # Iundefined method `build' for nil:NilClass

    @contact.date_entered = Date.today
    @campaigns = Campaign.find(:all, :order => "name")
    if params[:campaign_id].blank? 

    else
      @campaign = Campaign.find(params[:campaign_id])
      @contact.campaign_id = @campaign.id
    end

    if params[:company_id].blank?

    else
      @company = Company.find(params[:company_id])
      @contact.company_name = @company.name
    end

  end

  def create
    @contact = Contact.new(params[:contact])
    if @contact.save
      flash[:notice] = "Successfully created contact."
      redirect_to @contact
    else
      render :action => 'new'
    end
  end

  def edit
    @contact = Contact.find(params[:id])
    @campaigns = Campaign.find(:all, :order => "name")
  end

Here is a snippet of my error console: I am POSTING the attribute, but it is not CREATING in the Address table.... 这是我的错误控制台的摘要我正在发布属性,但在地址表中未创建。

Processing ContactsController#create (for 127.0.0.1 at 2010-05-12 21:16:17) 处理ContactsController#create(对于127.0.0.1在2010-05-12 21:16:17)

[POST] Parameters: {"commit"=>"Submit", "authenticity_token"=>"d8/gx0zy0Vgg6ghfcbAYL0YtGjYIUC2b1aG+dDKjuSs=", "contact"=>{"company_name"=>"Allyforce", "title"=>"", "campaign_id"=>"2", "address_attributes"=>{"street1"=>"abc"}, "fax"=>"", "phone"=>"", "last_name"=>"", "date_entered"=>"2010-05-12", "email"=>"", "first_name"=>"abc"}} [POST]参数:{“ commit” =>“ Submit”,“ authenticity_token” =>“ d8 / gx0zy0Vgg6ghfcbAYL0YtGjYIUC2b1aG + dDKjuSs =”,“ contact” => {“ company_name” =>“ Allyforce”,“ title” =>“ “,” campaign_id“ =>” 2“,” address_attributes“ => {” street1“ =>” abc“},”传真“ =>”“,”电话“ =>”“,”姓氏“ =>”“ ,“ date_entered” =>“ 2010-05-12”,“电子邮件” =>“”,“名字” =>“ abc”}}

Company Load (0.0ms)[0m [0mSELECT * FROM "companies" WHERE ("companies"."name" = 'Allyforce') LIMIT 1[0m 公司负载(0.0ms)[0m [0mSELECT * FROM“ companies” WHERE(“ companies”。“ name” ='Allyforce')LIMIT 1 [0m

Address Create (16.0ms)[0m 地址创建(16.0ms)[0m
[0;1mINSERT INTO "addresses" ("city", "zip", "created_at", "street1", "updated_at", "street2", "state") VALUES(NULL, NULL, '2010-05-13 04:16:18', NULL, '2010-05-13 04:16:18', NULL, NULL)[0m [0; 1mINSERT INTO“ addresses”(“ city”,“ zip”,“ created_at”,“ street1”,“ updated_at”,“ street2”,“ state”)VALUES(NULL,NULL,'2010-05-13 04 :16:18',NULL,'2010-05-13 04:16:18',NULL,NULL)[0m

Contact Create (0.0ms)[0m Contact Create(0.0ms)[0m
[0mINSERT INTO "contacts" ("company", "created_at", "title", "updated_at", "campaign_id", "address_id", "last_name", "phone", "fax", "company_id", "date_entered", "first_name", "email") VALUES(NULL, '2010-05-13 04:16:18', '', '2010-05-13 04:16:18', 2, 2, '', '', '', 5, '2010-05-12', 'abc', '')[0m [0mINSERT INTO“联系人”(“公司”,“ created_at”,“标题”,“ updated_at”,“ campaign_id”,“ address_id”,“ last_name”,“ phone”,“ fax”,“ company_id”,“ date_entered” ,“ first_name”,“ email”)VALUES(NULL,'2010-05-13 04:16:18','','2010-05-13 04:16:18',2,2,'',' ','',5,'2010-05-12','abc','')[0m

Just a banal question, if you using this in your contact form shouldn't be address in singular? 只是一个平凡的问题,如果您在联系表中使用此地址,是否不应该使用单数形式?

 <% f.fields_for :address, @contact.address do |builder| %>
   <p>
     <%= builder.label :street1, "Street 1" %> </br> 
     <%= builder.text_field :street1 %>
   <p>
 <% end %>

In your action you have also to do 在您的行动中,您还必须做

@ycontact.build_address

If you look at the source code your input field should look like. 如果您查看源代码,则输入字段应该看起来像。

< input type="text" size="30" name="contact[address_attributes][street1]" id="contact_address_attributes_street1"> <输入type =“ text” size =“ 30” name =“ contact [address_attributes] [street1]” id =“ contact_address_attributes_street1”>

I think you also have problems with your associations, if you store address_id in contact then 我认为您的关联也存在问题,如果您将address_id存储在联系人中,那么

class Contact < ActiveRecord::Base
  belongs_to :address
  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
  attr_accessible :street1
  has_many :contacts
end

And i think this is your case because you want to assign an address to multiple contacts. 我认为这是您的情况,因为您想为多个联系人分配一个地址。

You can also do in inverse, if you store your contact_id in your address model: 如果您将contact_id存储在地址模型中,也可以进行逆操作:

class Contact < ActiveRecord::Base
  has_one :address
  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
  attr_accessible :street1
  belongs_to :contact
end

In this case you cant have users with the same address. 在这种情况下,您不能让用户使用相同的地址。

Update 更新资料

In your user show.html.eb you can use 在您的用户show.html.eb中,您可以使用

<%= @contact.address.street1 %>

In your company's show.html.erb you can display the addresses like: 在您公司的show.html.erb中,您可以显示以下地址:

<% @company.addresses.each do |address| %>
  <%= address.street1 %>
  ...
<% end %>

On your user edit page the form fields should be the same as at new.html.erb just the form tag should look like: 在用户编辑页面上,表单字段应与new.html.erb相同,只是表单标签应类似于:

<% form_for @contact do |form| %>
  <%=render :partial=>'fields' %>
<% end %>

The fields partial contains all your fieds togheter with the: 该字段的一部分包含您所有的fied togheter,其中包括:

 <% f.fields_for :address, @contact.address do |builder| %>
   <p>
     <%= builder.label :street1, "Street 1" %> </br> 
     <%= builder.text_field :street1 %>
   <p>
 <% end %>

This should work. 这应该工作。

Update 2 更新2

You can access all the addresses which belong to a company with: 您可以通过以下方式访问属于公司的所有地址:

@company.addresses

If you have 如果你有

class Company<Activerecord::Base
    has_many :contacts
    has_many :addresses, :through=>:contacts
end

About the drafts, or default addresses. 关于草稿或默认地址。 You can have different options depending on your needs. 您可以根据需要选择不同的选项。 I you want the option that a contact could select one of the existing addresses from the database. 我想要一个选项,使联系人可以从数据库中选择现有地址之一。 You can do a select box in your contact form like: 您可以在联系表单中做一个选择框,例如:

 <%= form.select :address_id, options_from_collection_for_select(@company.addresses, 'id', 'street1')%>

Also you can use some fancy javascript to add or remove the address form, in that case if the user chooses one of the existing addresses. 另外,在这种情况下,如果用户选择现有地址之一,则可以使用一些精美的javascript来添加或删除地址表格。 In this case you have to remove the address_attributes from the form. 在这种情况下,您必须从表单中删除address_attributes。 I suggest to create a link with javascript code that adds the address_attributes and removes (toggle style). 我建议使用JavaScript代码创建一个添加address_attributes并删除(切换样式)的链接。

If each Address belongs to only one Contact, (like a home address), you could do: 如果每个地址仅属于一个联系人(例如家庭住址),则可以执行以下操作:

class Company < ActiveRecord::Base
  has_many :contacts
end

class Contact < ActiveRecord::Base
  belongs_to :company
  has_one :address
end

class Address < ActiveRecord::Base
  belongs_to :contact
end

Of course, you could just move the address columns into the Contact table and get rid of the Address model altogether. 当然,您可以仅将地址列移到Contact表中,并完全摆脱Address模型。

If each Address has multiple contacts (ie, the addresses are company facilities where the contacts work): 如果每个地址都有多个联系人(即,地址是联系人工作的公司设施):

class Company < ActiveRecord::Base
  has_many :contacts
end

class Contact < ActiveRecord::Base
  belongs_to :company
  belongs_to :address
end

class Address < ActiveRecord::Base
  has_many :contacts
end

You can add a has_many :through association to get company.addresses : 您可以添加has_many :through关联以获取company.addresses

class Company < ActiveRecord::Base
  has_many :contacts
  has_many :addresses, :through => :contacts
end

In both situations the address components (street, city, state, etc) are columns in the addresses table. 在两种情况下,地址组成部分(街道,城市,州等)都是地址表中的列。

The last part of your question really depends on the data distribution -- if you have only a few addresses, you could simply stick them in a select element with the main address as the default. 问题的最后一部分实际上取决于数据的分布-如果您只有几个地址,则可以简单地将其放在主地址为默认地址的select元素中。 With more addresses you might need an AJAXified form with autocomplete that search the addresses table. 使用更多地址,您可能需要具有自动完成功能的AJAXified表单来搜索地址表。

To get the new contacts/addresses into your tables, you might want to look at nested forms. 要将新的联系人/地址添加到表中,您可能需要查看嵌套表单。 Railscast 196 is a good introduction. Railscast 196是一个很好的介绍。

EDIT -- more about nested attributes 编辑-有关嵌套属性的更多信息

accepts_nested_attributes_for should work with either a has_many or has_one assocation, and should work with multiple levels of nesting. accepts_nested_attributes_for应该与has_manyhas_one关联一起使用,并且应该与多层嵌套一起使用。 It seems that you want to have a Contact belong to a Company, and an Address to belong to a Contact, in which case: 在这种情况下,您似乎想让一个联系人属于公司,而一个地址属于联系人。

class Company < ActiveRecord::Base
  has_many :contacts
  accepts_nested_attributes_for :contact
end

class Contact < ActiveRecord::Base
  belongs_to :company
  has_one :address # or has_many, if you prefer
end

class Address < ActiveRecord::Base
  belongs_to :contact
end

Then in the view use form_for and fields_for as described in the Railscast to get the nested form elements. 然后在视图中使用Railscast中所述的form_forfields_for来获取嵌套的表单元素。 This can be a bit tricky to get right if your form is unusual. 如果您的表格不正常,这可能会有点棘手。 There are excellent examples from ryanb here that cover several typical situations. 有来自ryanb很好的例子在这里涵盖了几种典型的情况。

Since you want an address to belong both to a company and to a contact, you have two choices. 由于您希望地址同时属于公司和联系人,因此有两种选择。 If you aren't going to ever need multiple addresses (which I might recommend against assuming), then you can put a "belongs_to :address" in both Company and Contact. 如果您永远不需要多个地址(建议您不建议使用多个地址),则可以在“公司”和“联系人”中都添加一个“ belongs_to:address”。 Address would then have both a "has_many :companies" and "has_many :contacts". 然后,地址将同时具有“ has_many:companies”和“ has_many:contacts”。

The better option that makes more sense is to use polymorphic associations, where the address table would have :addressable_type and :addressable_id columns to link back to either model. 更好的选择是使用多态关联,其中地址表将具有:addressable_type和:addressable_id列以链接回任一模型。

class Company < ActiveRecord::Base
  attr_accessible :name, :phone, :addresses

  has_many :contacts  
  accepts_nested_attributes_for :contacts

  has_many :addresses, :as => :addressable
  accepts_nested_attributes_for :addresses

end

class Contact < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :title, :phone, :fax, :email, :company, 
                  :date_entered, :campaign_id, :company_name

  belongs_to :company
  has_many :addresses, :as => :addressable
  accepts_nested_attributes_for :addresses
end

class Address < ActiveRecord::Base
  attr_accessible :street1

  belongs_to :addressable, :polymorphic => true
end

Now your trouble comes with wanting to have a single association "company.addresses" to get both it's address and those of its contacts. 现在,您的麻烦就在于希望有一个关联“ company.addresses”来获取其地址及其联系人的地址。 I might recommend staying away from this and using a different approach. 我可能建议您避免使用此方法,并使用其他方法。

You're going to want to map those addresses in the view to the correct record, so it might be best to separate them: 您将需要将视图中的那些地址映射到正确的记录,因此最好将它们分开:

<% form_for @company do |company_form| %>
  <% company_form.fields_for :addresses do |address_form| %>
    <%= address_form.text_field :street1 %>
  <% end %>
  <% company_form.fields_for :contacts do |contact_form| %>
    <% contact_form.fields_for :addresses do |contact_address_form| %>
      <%= contact_address_form.text_field :street1 %>
    <% end %>
  <% end %>
<% end %>

Your address table has the polymorphic columns like this: 您的地址表具有如下所示的多态列:

class CreateAddresses < ActiveRecord::Migration
  def self.up
    create_table :addresses do |t|
      t.string :street1
      t.string :addressable_type
      t.integer :addressable_id
      t.timestamps
    end
  end

  def self.down
    drop_table :addresses
  end
end

I'm not sure how you could keep all the linking straight if you don't nest the records individually like this. 如果您不像这样单独嵌套记录,我不确定如何保持所有链接直接。

If you do need to get all the addresses for a company for display purposes, you could use the standard ruby enumerable manipulations like collect to gather them together. 如果您确实需要获取公司的所有地址以用于显示,则可以使用标准的ruby可枚举操作(例如collect)将它们收集在一起。

Good luck! 祝好运!

I'd recommend to let the Contact have many addresses. 我建议让联系人有很多地址。 It happens anyways in the wild. 无论如何,它在野外发生。 If decided for only one, that would be has_one :address 如果只决定一个,那就是has_one :address

Oh and you must downcase them: has_many :Contacts must be has_many :contacts 哦,你必须小写它们: has_many :Contacts必须是has_many :contacts

In the Address model you reference with (database needs a addressable_id and addressable_type field) 在您引用的地址模型中(数据库需要一个addressable_idaddressable_type字段)

belongs_to :addressable, :polymorphic => true

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在rails中使用accepts_nested_attributes_for? - How to use accepts_nested_attributes_for with rails? 在没有accepts_nested_attributes_for的情况下,如何在Rails中更新嵌套属性? - How do I update Nested Attributes in Rails without accepts_nested_attributes_for? 在Rails中,如何使用accepts_nested_attributes_for创建嵌套对象? - In Rails, how do I create nested objects using accepts_nested_attributes_for? 创建新记录时如何使用accepts_nested_attributes_for? - How do you use accepts_nested_attributes_for when creating new records? 如何使用accepts_nested_attributes_for在连接表中创建&gt; 1个相关对象? - How can I use accepts_nested_attributes_for to create > 1 related object in a join table? 通过用于另一个对象的accepts_nested_attributes_for完成后,如何修改关联对象的创建? - How do I modify the creation of an associated object when done via accepts_nested_attributes_for for another object? Rails 3,多对多形式使用accepts_nested_attributes_for,如何正确设置? - Rails 3, many-to-many form using accepts_nested_attributes_for, how do I set up correctly? 在使用accepts_nested_attributes_for时,如何设置将拒绝现有记录的过滤器 - How do I set a filter that will reject existing records when using accepts_nested_attributes_for 如何使simple_form与accepts_nested_attributes_for一起做什么 - How to make simple_form do what I want with accepts_nested_attributes_for 使用accepts_nested_attributes_for时如何在联接模型上设置属性? - How do I set an attribute on the join model when using accepts_nested_attributes_for?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM