Rails 4将多态关联转换为has_many

时间:2017-04-10 14:11:48

标签: ruby-on-rails activerecord polymorphic-associations

Manager有多个contacts通过多态关联

class Manager
  has_many :contacts, as: :contactable
end

class Contact
  belongs_to :contactable, polymorphic: true
end

关系正常,但现在联系人可以与许多managers相关联。

因此,添加了一个新模型Contactable,一个联接表'contactables',并将contactable_idcontactable_type字段从contacts表移至contactables表。

class Contactable
  belongs_to :contact
  belongs_to :contactable, polymorphic: true
end

现在对ManagerContact关系感到困惑,因为它会如何在模型中正确定义以使其正常工作。试过以下但不起作用:

class Manager
  has_many :contacts, through: :contactables, source: :contactable, source_type: "Contact"
end 

1 个答案:

答案 0 :(得分:1)

所以我检查了这个有趣的话题,并告诉我所知道的。

has_many :through中照常创建对象时:

class Contact
  has_many :contactables
  has_many :managers, :through => :contactables
end

class Manager 
  has_many :contactables
  has_many :contacts, :through => :contactables
end 

class Client 
  has_many :contactables
  has_many :contacts, :through => :contactables
end 

class Contactable 
  belongs_to :contact
  belongs_to :manager
  belongs_to :client
end 

您可以使用每个引用对象的外键。多态似乎是一个很好的解决方案。所以:

class Contactable 
  belongs_to :contact
  belongs_to :polymorphic_model, polymorphic: true
end 

class Contact 
  has_many :contactables
  has_many :managers, :through => :contactables, :source => :polymorphic_model, :source_type => 'Manager'
end 

class Manager 
  has_many :contactables, :as => :polymorphic_model
  has_many :contacts, :through => :contactables
end 
  

设置:as选项表示这是一个多态   协会

:source => :polymorphic_model用于告诉Rails从子类中获取相关对象。 :source表示与:class_name相同。如果没有此选项,Rails将尝试从Contactables表中获取关联的Manager,同时应通过虚拟Polymorphic_model访问它。

通过将belongs_to :polymorphic_model添加到Contactable,您可以启用联系人(因为belongs_to :contact已经坐在那里,因为have_many)与管理员或客户关联,因为那是多态关联所做的 - 引用两个或更多父母表。因为联系Manager.create!(name: "Bravo") => #<Manager id: 1, created_at: "2017-04-12 12:17:41", updated_at: "2017-04-12 12:17:41", name: "Bravo"> Manager.create!(name: "Johnny") => #<Manager id: 2, created_at: "2017-04-12 12:18:24", updated_at: "2017-04-12 12:18:24", name: "Johnny"> Contact.create!(number:"123") => #<Contact id: 1, created_at: "2017-04-12 12:18:59", updated_at: "2017-04-12 12:18:59", number: 123> c = Contactable.new c.contact = Contact.first c.unit = Manager.first c => #<Contactable id: nil, unit_type: "Manager", created_at: nil, updated_at: nil, unit_id: 1, contact_id: 1> 可联系人,同一个联系人对象可以与许多经理或客户关联。因此,在您了解它之后,它看起来非常简单 - 连接模型属于Contact,Joined模型也通过Polymorphic关联保存对Manager和Client的引用。因此,为了使Contact拥有许多管理器,您可以创建另一个属于同一个Contact但位于不同Manager的Contactable对象。看起来效率不高,但我个人而言,不知道更好的方式..

以下是经过测试的证明:

cc = Contactable.new
cc.contact = Contact.first
cc.unit = Manager.last
cc
 => #<Contactable id: nil, unit_type: "Manager", created_at: nil, updated_at: nil, unit_id: 4, contact_id: 1>

现在将另一个Manager设置为同一个联系人,我们创建一个新的Contactable:

Contact.first.managers

并获得所有关联:

contact_id
unit_id
unit_type

可联系人的数据库:

Whileprintingrecords;
stringvar array sMessage := split({Inventory.MessageText},",");
If UBound(sMessage ) > 0 then
(
   Trim(sMessage [1]) & Chr(13) & Trim(sMessage [2]);
)

@Bill Karwin的一句有趣的话:

  

多态关联设计打破了关系规则   数据库设计。我不建议使用它。

但他很久以前写过这篇文章。现在可能无关紧要。

Why can you not have a foreign key in a polymorphic association?