Rails开发细节《七》ActiveRecord Associations关联
1.为什么需要关联
很多时候,比如说电子商务中的用户和订单,一个用户会有很多的订单,一个订单只属于一个用户,这就是一种关联。
在创建订单的时候需要用户主键作为外键,删除用户的的同时需要删除用户的订单。
在rails中可以向下面这样订单关联。
- class Customer < ActiveRecord::Base
- has_many :orders, :dependent => :destroy
- end
- class Order < ActiveRecord::Base
- belongs_to :customer
- end
就可以像下面这样创建订单,删除用户。
- @order = @customer.orders.create(:order_date => Time.now)
- @customer.destroy
2.关联的类型
有下面6中关联。
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
2.1.belongs_to
belongs_to是一种一对一的关联。表达一种属于的关系。
就像一个订单只能属于个用户。在订单表会有一个字段存储用户主键,这个字段是订单表的外键。
- class Order < ActiveRecord::Base
- belongs_to :customer
- end
2.2.has_one
has_one也是一种一对一的关联。表达一种有一个的关系。
就像一个供应商只能有一个账户。账户表有一个供应商主键,是账户表的外键。
- class Supplier < ActiveRecord::Base
- has_one :account
- end
2.3.has_many
has_many是一种一对多的关联。表达有多个的关系。
就像一个用户有多个订单。
- class Customer < ActiveRecord::Base
- has_many :orders
- end
has_many关联的名称需要使用复数形式。
2.4.has_many :through
has_many是一种多对多的关联。存在一个中间的model。是通过中间model建立关联。
有一个场景就是病人看病,但是需要和医生进行预约。一个医生会有多个预约记录,一个病人也会有多个预约记录。在预约表中会有医生主键和病人主键。
- class Physician < ActiveRecord::Base
- has_many :appointments
- has_many :patients, :through => :appointments
- end
- class Appointment < ActiveRecord::Base
- belongs_to :physician
- belongs_to :patient
- end
- class Patient < ActiveRecord::Base
- has_many :appointments
- has_many :physicians, :through => :appointments
- end
其实就是把医生和病人的预约关系单独表存放,这张表也会有主键。
- class Document < ActiveRecord::Base
- has_many :sections
- has_many :paragraphs, :through => :sections
- end
- class Section < ActiveRecord::Base
- belongs_to :document
- has_many :paragraphs
- end
- class Paragraph < ActiveRecord::Base
- belongs_to :section
- end
2.5.has_one :through
- class Supplier < ActiveRecord::Base
- has_one :account
- has_one :account_history, :through => :account
- end
- class Account < ActiveRecord::Base
- belongs_to :supplier
- has_one :account_history
- end
- class AccountHistory < ActiveRecord::Base
- belongs_to :account
- end
2.6.has_and_belongs_to_many
has_and_belongs_to_many也是一种多对多的关联。不存在一个中间的model。关系在单独的表中存放,但是这张表没有单独的id,只有双方的id。
- class Assembly < ActiveRecord::Base
- has_and_belongs_to_many :parts
- end
- class Part < ActiveRecord::Base
- has_and_belongs_to_many :assemblies
- end
2.7.选择belongs_to还是has_one
belongs_to一般放在有外键的model中,表达一种属于的关系。has_one表达一种拥有的关系。
- class Supplier < ActiveRecord::Base
- has_one :account
- end
- class Account < ActiveRecord::Base
- belongs_to :supplier
- end
供应商有一个账号,一个账号属于供应商。
2.8.选择has_many :through还是has_and_belongs_to_many
如果你需要关系model作为独立的实体,就选择has_many :through;不需要独立的实体就选择has_and_belongs_to_many。
- class Assembly < ActiveRecord::Base
- has_and_belongs_to_many :parts
- end
- class Part < ActiveRecord::Base
- has_and_belongs_to_many :assemblies
- end
- class Assembly < ActiveRecord::Base
- has_many :manifests
- has_many :parts, :through => :manifests
- end
- class Manifest < ActiveRecord::Base
- belongs_to :assembly
- belongs_to :part
- end
- class Part < ActiveRecord::Base
- has_many :manifests
- has_many :assemblies, :through => :manifests
- end
如果在连接实体上需要验证,回调,或者额外的属性,那就需要使用has_many :through。
2.9.polymorphic
使用polymorphic关联,一个model可以多个model。
就像图片model,既属于员工model,也属于产品model。就是说员工和产品都有图片,他们共享同一个图片model。
- 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
- 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
- class CreatePictures < ActiveRecord::Migration
- def change
- create_table :pictures do |t|
- t.string :name
- t.references :imageable, :polymorphic => true
- t.timestamps
- end
- end
- end
2.10.自连接
有时候,实体会连接自己。
就好比员工表,有些员工同时又是经理,会领导一部分的员工,这样就会造成自连接。
- class Employee < ActiveRecord::Base
- has_many :subordinates, :class_name => "Employee",
- :foreign_key => "manager_id"
- belongs_to :manager, :class_name => "Employee"
- end
本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/1019921,如需转载请自行联系原作者