【问题标题】:Rails 4 converting a polymorphic association to has_many throughRails 4通过将多态关联转换为has_many
【发布时间】:2017-04-10 14:11:47
【问题描述】:

一个Manager 通过多态关联有许多contacts

class Manager
  has_many :contacts, as: :contactable
end

class Contact
  belongs_to :contactable, polymorphic: true
end

关系工作正常,但现在一个联系人可以与多个managers 关联。

因此,添加了一个新模型 Contactable、一个连接表“联系人”并将 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 

【问题讨论】:

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


    【解决方案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,您可以使Contact(女巫已经坐在那里,因为belongs_to :contact)与经理或客户相关联,因为这就是多态关联所做的 - 引用两个或多个父表。并且因为 Contact have_many Contactables,同一个 Contact 对象可以与许多经理或客户相关联。所以在你理解之后,看起来真的很简单——Joined 模型属于Contact 并且Joined 模型还通过多态关联持有对Manager 和Client 的引用。因此,为了让 Contact 拥有多个经理,您需要创建另一个属于同一个 Contact,但属于不同 Manager 的 Contactable 对象。看起来效率不高,但就我个人而言,不知道更好的方法..

    这是一个经过测试的证明:

    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>
    

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

    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>
    

    并获得所有关联:

    Contact.first.managers
    

    联系人的数据库:

    contact_id
    unit_id
    unit_type
    

    @Bill Karwin 的一句有趣的话:

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

    但这是他很久以前写的。现在可能无关紧要。

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

    【讨论】:

    • 我认为我们需要 source_type 以及 Contact 模型中的 source 选项。即:source_type =&gt; 'Manager'
    • 是的,我之前没有添加过,因为它是可选的——只是为了让生活更轻松。现在也包括在内了
    猜你喜欢
    • 2014-12-16
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-16
    • 2013-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多