这是一个在rails中的多态关联的一个简明教程。
最近的一个ruby on rails项目,用户和公司的模型都有地址。
我要创建一个地址表,包含用户和公司表的引用,比直接做下去要好一点,这回让我的数据库设计保持干净。
我的第一印象是,这似乎很难实现,外面所有的讨论及教程都只说明了在model如何设置,但是并没有说明在controller和view如何使用它。我好一顿放狗,也没有得到太多的帮助。
令我感到惊喜是其实在rails设置并使用多态表单是很简单的。
首先依然是先设置model结构:
1
2
3
4
5
6
7
8
9
10
11
|
class
Company< ActiveRecord::Base
has_one
:address
,
:as
=>;
:addressable
,
:dependent
=>
:destroy
end
class
User < ActiveRecord::Base
has_one
:address
,
:as
=>
:addressable
,
:dependent
=>
:destroy
end
class
Address < ActiveRecord::Base
belongs_to
:addressable
,
:polymorphic
=>
true
end
|
接下来是创建一个Address表来保存地址:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class
CreateAddresses < ActiveRecord::Migration
def
self
.up
create_table
:addresses
do
|t|
t.string
:street_address1
,
:null
=>
false
t.string
:street_address2
t.string
:city
,
:null
=>
false
t.string
:region
,
:null
=>
false
t.string
:postcode
,
:null
=>
false
,
:limit
=>
55
t.integer
:addressable_id
,
:null
=>
false
t.string
:addressable_type
,
:null
=>
false
t.timestamps
end
end
def
self
.down
drop_table
:addresses
end
end
|
接下来是controller,你只需要修改controller中的"new","create","edit","update"四个action,好让需要的时候可以访问和修改address。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
class
CompaniesController < ApplicationController
def
new
@company
= Company.
new
@company
.address = Address.
new
end
def
edit
@company
= Company.find(params[
:id
])
@company
.address = Address.
new
unless
@company
.address !=
nil
end
def
create
@company
= Company.
new
(params[
:company
])
@company
.address = Address.
new
(params[
:address
])
if
@company
.save
@company
.address.save
flash[
:notice
] =
'Company was successfully created.'
redirect_to(
@company
)
else
render
:action
=>
'new'
end
end
def
update
@company
= Company.find(params[
:id
])
if
@company
.update_attributes(params[
:company
])
@company
.address.update_attributes(params[
:address
])
flash[
:notice
] =
'Company was successfully updated.'
redirect_to(
@company
)
else
render
:action
=>
'edit'
end
end
end
|
最后一件事是让address在表单中可以正常工作,我们这里使用field_for方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<% form_for(
@company
)
do
|f| %>
<%= f.error_messages %>
<dl>
<%= f.text_field
:name
%>
<%= f.text_field
:telephone
%>
<%= f.text_field
:fax
%>
<%= f.text_field
:website_url
%>
</dl>
<% fields_for(
@company
.address)
do
|address_fields| %>
<%= address_fields.hidden_field
:addressable_id
%>
<%= address_fields.hidden_field
:addressable_type
%>
<dl>
<%= address_fields.text_field
:street_address1
%>
<%= address_fields.text_field
:street_address2
%>
<%= address_fields.text_field
:city
%>
<%= address_fields.text_field
:region
%>
<%= address_fields.text_field
:postcode
%>
</dl>
<%
end
%>
<%
end
%>
|
到这就应该可以正常工作了。
有人要问了,如果我去的了address对象,能否反向取得Company或者User对象呢?答案当然是肯定的。
1
2
3
|
@address
= Address.find(params[
:id
])
@address
.addressable
这样就可以访问了。
|