在Rails中使用polymorphic (多态、虚拟) 关联(转)

在Rails中使用polymorphic (多态、虚拟) 关联

来自 http://hi.baidu.com/rainchen/item/034bd0d60a24a32938f6f7dd

现有个场景,有两个model:person和album,需要添加一个图片来做为其头像/封面。添加一个image model,按照以往需要对这几个model做以下关联设置:

class Person < ActiveRecord::Base
    has_one :image, :dependent => :destroy
end

class Album < ActiveRecord::Base
    has_one :image, :dependent => :destroy
end

class Image < ActiveRecord::Base
    belongs_to :person
    belongs_to :album
end

相应的image的migration要添加上关联字段:
t.column :person_id, :integer, :null => false, :default => 0
t.column :album_id, :integer, :null => false, :default => 0

不复杂,但是麻烦,如果以后加个book model之类的,也需要有个图做封面的,那又要改image model里的关联和migration了,一点都不DRY。

这时就该 polymorphic 上场了。

先上代码:

class Person < ActiveRecord::Base
    has_one :image, :as => :iconable, :dependent => :destroy
end

class Album < ActiveRecord::Base
    has_one :image, :as => :iconable, :dependent => :destroy
end

class Image < ActiveRecord::Base
    belongs_to :iconable, :polymorphic => true
end

解释:

      polymorphic的实现是添加一个虚拟的第三方model(作为原model的一个形态)来维护彼此的联系。
      首先person和album在关联时添加一个:as选项,设置一个虚拟的iconable model,可以直白理解为“每个person都有一个iconable形态的image”。
      然后设置image属于iconable,且设置:polymorphic => true 表明这个iconable model是虚的,仅仅用来维持关联。
      iconable是虚的,但用来维持彼此联系的“证据”还是必须实实在在的,修改image的migration为:

# 关联对象的id
t.column :iconable_id, :integer, :null => false, :default => 0
# 关联对象的类名,如:Person
t.column :iconable_type, :string, :null => false, :default => ''


这样就可以在controller里这样使用:
# 添加:
@person = Person.new(params[:person])
@person.build_image(params[:image])
@person.save

# 读取:
@person.image

# image 的属主:
@person.iconable

相关参考:

SimplePolymorphicAssociation

HowToUsePolymorphicAssociations

UnderstandingPolymorphicAssociations

has_many_polymorphs:简化多对多映射

has_many_polymorphs for dummies

原文地址:https://www.cnblogs.com/wws19125/p/3057810.html