每天一剂Rails良药之Many to Many Relationships Where the Relationship Itself Has Data
通常我们面临多对多时的处理方法是建立一个关系表,然后has_and_belongs_to_many
如果我们的关系表有其他属性,我们通过声明join table来放置关系表的其他属性
而当关系表本身具有其他属性时,我们可以通过join model来处理
如Magazine和Reader的多对多关系表Subscription:
def self.up
create_table :magazines do |t|
t.column :title, :string
end
create_table :readers do |t|
t.column :name, :string
end
create_table :subscriptions do |t|
t.column :magazine_id, :integer
t.column :reader_id, :integer
t.column :last_renewal_on, :date
t.column :length_in_issues, :integer
end
end
我们建立了magazines、readers和关系表subscriptions的migration,其中关系表中有两个一般属性
然后我们可以这样定义它们三者的model:
class Subscription < ActiveRecord::Base
belongs_to :magazine
belongs_to :reader
end
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :readers, :through => :subscriptions
end
class Reader < ActiveRecord::Base
has_many :subscriptions
has_many :magazines, :through => :subscriptions
end
这样我们通过Subscription这个join model建立了Magazine和Reader的多对多关系
magazine = Magazine.create(...)
reader = Reader.create(...)
subscription = Subscription.create(...)
magazine.subscriptions << subscription
reader.subscriptions << subscription
subscription.save
这样我们就保存了一个Subscription对象我们可以通过magazine.readers或者reader.magazines查看关联的对象
我们还可以给出一些has_many的options,例如得到半年的subscribers:
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :readers, :through => :subscriptions
has_many :semiannual_subscribers,
:through => :subscriptions,
:class_name => "Reader",
:conditions => ['length_in_issues = 6']
end
这样我们可以通过magazine.semiannual_subscribers来得到半年的subscribers