编辑我的问题以简明扼要并更新我已完成的工作:
如何为公司建立多个地址并为联系人分配单个地址,并在创建或编辑联系人时分配这些地址?
我想使用嵌套属性在创建新联系人时添加地址。该地址作为自己的模型存在,因为我可能希望选项从现有地址下拉而不是从头开始。
我似乎无法让它发挥作用。我得到一个未定义的方法`build'为nil:NilClass错误
以下是我的联系人模型:
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中创建字段的方法,以便当有人创建新的联系人时,他们将地址传递给地址模型并将该地址与联系人关联:
<% 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
以下是我的错误控制台的片段: 我正在POST属性,但它不是在Address表中创建....
处理ContactsController #create (适用于2010-05-12 21:16:17的127.0.0.1)
[POST]参数: { “提交”=&gt; “中提交”, “authenticity_token”=&gt; “中D8 / gx0zy0Vgg6ghfcbAYL0YtGjYIUC2b1aG + dDKjuSs =”, “接触”=&GT; { “COMPANY_NAME”=&gt; “中Allyforce”, “title”=&gt;“”,“campaign_id”=&gt;“2”, “address_attributes”=&GT; { “street1”=&gt; “中ABC”}, “fax”=&gt;“”,“phone”=&gt;“”, “姓氏”=&gt; “中”, “date_entered”=&gt; “中2010-05-12”, “email”=&gt;“”,“first_name”=&gt;“abc”}}
公司负荷(0.0ms)[0m [0mSELECT *来自“公司”WHERE(“公司”。“name”='Allyforce') 限制1 [0m
地址创建(16.0ms)[0m
[0; 1mINSERT INTO“地址”(“城市”, “zip”,“created_at”,“street1”, “updated_at”,“street2”,“州”) VALUES(NULL,NULL,'2010-05-13 04:16:18',NULL,'2010-05-13 04:16:18',NULL,NULL)[0m联系创建(0.0ms)[0m
[0mINSERT INTO“contacts”(“公司”, “created_at”,“title”,“updated_at”, “campaign_id”,“address_id”, “last_name”,“手机”,“传真”, “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
答案 0 :(得分:3)
只是一个平庸的问题,如果你在联系表格中使用这个问题不应该以单数形式提出?
<% f.fields_for :address, @contact.address do |builder| %>
<p>
<%= builder.label :street1, "Street 1" %> </br>
<%= builder.text_field :street1 %>
<p>
<% end %>
在你的行动中你还要做
@ycontact.build_address
如果查看源代码,输入字段应如下所示。
&LT;输入类型=“文本”大小=“30” 名称= “接触[address_attributes] [street1]” ID = “contact_address_attributes_street1” &GT;
如果您将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 %>
字段部分包含所有你的fieds togheter with:
<% 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并删除(切换样式)。
答案 1 :(得分:1)
如果每个地址只属于一个联系人(如家庭住址),您可以这样做:
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 here提供了很好的例子,涵盖了几种典型的情况。
答案 2 :(得分:1)
由于您希望地址属于公司和联系人,因此您有两种选择。如果您不需要多个地址(我建议不要假设),那么您可以在公司和联系人中添加“belongs_to:地址”。地址将同时具有“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)将它们聚集在一起。
祝你好运!答案 3 :(得分:0)
我建议让联系人有很多地址。它总是发生在野外。如果只决定一个,那就是has_one :address
哦,你必须将它们包括在内:has_many :Contacts
必须是has_many :contacts
在您引用的地址模型中(数据库需要addressable_id
和addressable_type
字段)
belongs_to :addressable, :polymorphic => true