您的位置:首页 > 大数据 > 人工智能

rails中的模型关联(进阶篇)

2016-07-26 15:02 567 查看

rails中的模型关联(进阶篇)

2016-07-26 15:02
110人阅读 评论(0)
收藏
举报

目录(?)[+]

rails中的模型关联(进阶篇)
http://www.xingishere.com/blogs/model_association
总结了一些 rails 模型关联,有些可能不是很常见,但是会很有用,在这里和大家分享一下。


1. has_many :through

has_many 的用法大家可能都很熟悉,但是后面跟一个 `:through` 呢? has_many :through 通常表示两个模型之间的多对多的关系是通过(through)另外一个 model 关联起来的,举个例子:一个男孩儿可以通过约会交往多个女孩儿,同时一个女孩儿可以通过约会交往多个男孩儿,相关的`model`代码如下:
class Boy < ActiveRecord::Base
has_many :appointments
has_many :girls, :through => :appointments
end

class Appointment < ActiveRecord::Base
belongs_to :boy
belongs_to :girl
end

class Girl < ActiveRecord::Base
has_many :appointments
has_many :boys, :through => :appointments
end


注:此时 boy 和 girl 是通过 appointments 关联,所以 boy 表不需要 girl_id,girl 表也不需要 boy_id,只要在 appointment 表声明一个 boy_id和一个 girl_id 即可
rails g scaffold boy name:string age:integer
rails g scaffold girl name:string age:integer
rails g model appointment boy_id:integer girl_id:integer content:string


has_many :through
 还可以简化嵌套的关联关系,举个例子:某公司有多名开发(developer),每个开发有多次的加班(extra_work),可能你想知道某公司有多少的加班,你应该这样做:
class Company < ActiveRecord::Base
has_many :developers
has_many :extra_works, :through => :developers
end

class Developer < ActiveRecord::Base
belongs_to :company
has_many :extra_works
end

class ExtraWork < ActiveRecord::Base
belongs_to :developer
belongs_to :company
end


[email protected]

_works.count 了。


2. has_one :through

通过上面介绍的 has_many :through,你应该很容易了解 has_one :through 的适用场景和使用方法了。需要注意的是数据库模型 id 的声明。


3. has_and_belongs_to

has_and_belongs_to 直接建立两个 model 的多对多关系,不需要中间 model,举个例子:一名开发(developer)可以有多个项目(project),一个项目可以有多个开发
class Developer < ActiveRecord::Base
has_and_belongs_to_many :projects
end

class Project < ActiveRecord::Base
has_and_belongs_to_many :developers
end


注:这种声明关系需要在数据库中创建中间表


4. 谁应该 has_one? 谁应该 belongs_to?

当你想建立一个一对一的关系时,你需要在他们的 model 上分别声明 has_one 和 belongs_to,那么谁应该 has_one,谁应该 belongs_to 呢?这要看 外键 的位置,而且你需要考虑到这两个 model 的实际意义,比如说:“每个公民都有且只有一个身份证”要比“每个身份证都有一个公民”更符合实际。
class Citizen < ActiveRecord::Base
has_one :card
end

class Card < ActiveRecord::Base
belongs_to :citizen
end


正确的migration应该是这样
class CreateCitizens < ActiveRecord::Migration
def change
create_table :citizens do |t|
t.string  :name
t.timestamps
end

create_table :cards do |t|
t.integer :citizen_id
t.string  :card_number
t.timestamps
end
end
end


在当前版本的 rails 中,t.integer 那一行应该用 t.references :citizen 代替。


5. has_many :through 还是 has_and_belongs_to_many?

Rails 提供了两种建立多对多关系的实现方法,简单一点的时是 has_and_belongs_to_many,他直接建立关系,另外一种是声明 has_and_belongs_to_many,它需要通过一个中间 model 建立关系。记住一个最简单的规则:如果你把这个关系模型(比如上面的 appointment )当做一个独立的实体进行操作,你就需要使用 has_many :through,否则就使用 has_and_belongs_to_many 好了(你还是需要在数据库中创建一个中间表)


6. 多态关系

Rails model 还有一种比较“绕”的关系,我把它翻译为“多态关系”,通过多态关系,一个 model 可以通过一个关系 belongs_to 多个 model,举个例子:你有一个 picture model,它 belongs_to employee 或者 product,你应该做如下声明:
class Picture < ActiveRecord::Base
belongs_to :imageable, :polymorphic => true
end

class Employee < ActiveRecord::Base
has_many :pictures, :as => :imageable
end

class Product < ActiveRecord::Base
has_many :pictures, :as => :imageable
end


你可以认为一个多态的 belongs_to 声明创建了一个其它 model 使用的接口,你可以使用 @employee.pictures 和 @product.pictures。如果你有一个 Picture 实例,你可以通过 @picture.imageable 来获取它的父元素,为了达到这一目的,你需要指定外键和一个 type 字段来声明这个多态接口。
class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string  :name
t.integer :imageable_id
t.string  :imageable_type
t.timestamps
end
end
end


有一个更简单的方法
ae2a
,那就是使用 t.references 和 polymorphic
class CreatePictures < ActiveRecord::Migration
def change
create_table :pictures do |t|
t.string :name
t.references :imageable, :polymorphic => true
t.timestamps
end
end
end


7. 自链接

在设计一个数据模型的时候,你有时可能需要找到一个 model 对它自己的关系,举个例子:你想要在一个数据库模型中存储所有的员工,但是你还想在这里声明:高管,低级人员等,你可以这么做:
class Employee < ActiveRecord::Base
has_many :subordinates, :class_name => "Employee",
:foreign_key => "manager_id"
belongs_to :manager, :class_name => "Employee"
end


这样你就可以使用 @employee.subordinates和 @employee.manager了。

关于 rails 的模型关联先说到这里,我们下期再见
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: