[英]How do I use accepts_nested_attributes_for?
為簡潔起見,請編輯我的問題並更新我所做的事情:
如何為公司具有多個地址建模,並為聯系人分配一個地址,並在創建或編輯聯系人時進行分配?
我想使用嵌套屬性來在創建新聯系人時添加地址。 該地址作為其自身的模型存在,因為我可能希望該選項從現有地址下拉而不是從頭輸入。
我似乎無法正常工作。 我為nil:NilClass錯誤得到一個未定義的方法'build'
這是我的通訊錄模型:
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
這是我的地址模型:
class Address < ActiveRecord::Base
attr_accessible :street1, :street2, :city, :state, :zip
has_many :contacts
end
我想在創建新聯系人時,訪問屬於公司的其他聯系人的所有地址。 所以這是我代表公司的方式:
class Company < ActiveRecord::Base
attr_accessible :name, :phone, :addresses
has_many :contacts
has_many :addresses, :through => :contacts
end
這是我嘗試在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 %>
當我嘗試編輯時,“街道1”的字段為空白。 而且我不知道如何顯示show.html.erb中的值。
最下面是我的錯誤控制台-似乎無法在地址表中創建值:
我的聯系人控制器如下:
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
這是我的錯誤控制台的摘要:我正在發布屬性,但在地址表中未創建。
處理ContactsController#create(對於127.0.0.1在2010-05-12 21:16:17)
[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”}}
公司負載(0.0ms)[0m [0mSELECT * FROM“ companies” WHERE(“ companies”。“ name” ='Allyforce')LIMIT 1 [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)[0mContact Create(0.0ms)[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
只是一個平凡的問題,如果您在聯系表中使用此地址,是否不應該使用單數形式?
<% f.fields_for :address, @contact.address do |builder| %>
<p>
<%= builder.label :street1, "Street 1" %> </br>
<%= builder.text_field :street1 %>
<p>
<% end %>
在您的行動中,您還必須做
@ycontact.build_address
如果您查看源代碼,則輸入字段應該看起來像。
<輸入type =“ text” size =“ 30” name =“ contact [address_attributes] [street1]” id =“ contact_address_attributes_street1”>
我認為您的關聯也存在問題,如果您將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
我認為這是您的情況,因為您想為多個聯系人分配一個地址。
如果您將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
在這種情況下,您不能讓用戶使用相同的地址。
更新資料
在您的用戶show.html.eb中,您可以使用
<%= @contact.address.street1 %>
在您公司的show.html.erb中,您可以顯示以下地址:
<% @company.addresses.each do |address| %>
<%= address.street1 %>
...
<% end %>
在用戶編輯頁面上,表單字段應與new.html.erb相同,只是表單標簽應類似於:
<% form_for @contact do |form| %>
<%=render :partial=>'fields' %>
<% end %>
該字段的一部分包含您所有的fied togheter,其中包括:
<% f.fields_for :address, @contact.address do |builder| %>
<p>
<%= builder.label :street1, "Street 1" %> </br>
<%= builder.text_field :street1 %>
<p>
<% end %>
這應該工作。
更新2
您可以通過以下方式訪問屬於公司的所有地址:
@company.addresses
如果你有
class Company<Activerecord::Base
has_many :contacts
has_many :addresses, :through=>:contacts
end
關於草稿或默認地址。 您可以根據需要選擇不同的選項。 我想要一個選項,使聯系人可以從數據庫中選擇現有地址之一。 您可以在聯系表單中做一個選擇框,例如:
<%= form.select :address_id, options_from_collection_for_select(@company.addresses, 'id', 'street1')%>
另外,在這種情況下,如果用戶選擇現有地址之一,則可以使用一些精美的javascript來添加或刪除地址表格。 在這種情況下,您必須從表單中刪除address_attributes。 我建議使用JavaScript代碼創建一個添加address_attributes並刪除(切換樣式)的鏈接。
如果每個地址僅屬於一個聯系人(例如家庭住址),則可以執行以下操作:
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
當然,您可以僅將地址列移到Contact表中,並完全擺脫Address模型。
如果每個地址都有多個聯系人(即,地址是聯系人工作的公司設施):
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
您可以添加has_many :through
關聯以獲取company.addresses
:
class Company < ActiveRecord::Base
has_many :contacts
has_many :addresses, :through => :contacts
end
在兩種情況下,地址組成部分(街道,城市,州等)都是地址表中的列。
問題的最后一部分實際上取決於數據的分布-如果您只有幾個地址,則可以簡單地將其放在主地址為默認地址的select元素中。 使用更多地址,您可能需要具有自動完成功能的AJAXified表單來搜索地址表。
要將新的聯系人/地址添加到表中,您可能需要查看嵌套表單。 Railscast 196是一個很好的介紹。
編輯-有關嵌套屬性的更多信息
accepts_nested_attributes_for
應該與has_many
或has_one
關聯一起使用,並且應該與多層嵌套一起使用。 在這種情況下,您似乎想讓一個聯系人屬於公司,而一個地址屬於聯系人。
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
然后在視圖中使用Railscast中所述的form_for
和fields_for
來獲取嵌套的表單元素。 如果您的表格不正常,這可能會有點棘手。 有來自ryanb很好的例子在這里涵蓋了幾種典型的情況。
由於您希望地址同時屬於公司和聯系人,因此有兩種選擇。 如果您永遠不需要多個地址(建議您不建議使用多個地址),則可以在“公司”和“聯系人”中都添加一個“ belongs_to:address”。 然后,地址將同時具有“ has_many:companies”和“ has_many:contacts”。
更好的選擇是使用多態關聯,其中地址表將具有: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
現在,您的麻煩就在於希望有一個關聯“ company.addresses”來獲取其地址及其聯系人的地址。 我可能建議您避免使用此方法,並使用其他方法。
您將需要將視圖中的那些地址映射到正確的記錄,因此最好將它們分開:
<% 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 %>
您的地址表具有如下所示的多態列:
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
如果您不像這樣單獨嵌套記錄,我不確定如何保持所有鏈接直接。
如果您確實需要獲取公司的所有地址以用於顯示,則可以使用標准的ruby可枚舉操作(例如collect)將它們收集在一起。
祝好運!
我建議讓聯系人有很多地址。 無論如何,它在野外發生。 如果只決定一個,那就是has_one :address
哦,你必須小寫它們: has_many :Contacts
必須是has_many :contacts
在您引用的地址模型中(數據庫需要一個addressable_id
和addressable_type
字段)
belongs_to :addressable, :polymorphic => true
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.