【问题标题】:Double polymorphic association双多态关联
【发布时间】:2013-02-28 07:30:08
【问题描述】:

在我的 rails 应用程序中,我有两个模型: PersonCompany。我需要指定这些对象的任何对之间的多对多关系。所以我应该可以这样做:

@connections = @person.connections

其中@connectionsPersonCompany 对象的数组。

现在我为此创建了 ConnectionBinding 模型,但它不能按预期工作:

class ConnectionBinding < ActiveRecord::Base
  belongs_to :connect_from, polymorphic: true
  belongs_to :connect_to,   polymorphic: true
end

它认为ActiveRecord::HasManyThroughAssociationPolymorphicSourceError 异常

有人已经解决了这个问题吗?任何建议表示赞赏。

【问题讨论】:

  • 我想知道 STI 是否能以某种方式提供帮助。

标签: ruby-on-rails has-many-through polymorphic-associations


【解决方案1】:

一个问题:

module Linkable
  extend ActiveSupport::Concern

  included do
    has_many :links_to, as: :linkable_to, class_name: 'Link' # [this]->[other object]
    has_many :links_from, as: :linkable_from, class_name: 'Link' # [other object]->[this]
  end
end

链接表:

class Link < ActiveRecord::Base

  #The idea for this class is to by a double polymorphic table, linking an object to another object
  belongs_to :linkable_from, :polymorphic => true
  belongs_to :linkable_to, :polymorphic => true
end

【讨论】:

  • 这就是我想要的。可悲的是,我收到一条错误消息ActiveRecord::AssociationTypeMismatch (TreeLeaf(#47140839607440) expected, got #&lt;TreeNode id: nil, created_at: nil, updated_at: nil&gt; which is an instance of TreeNode(#70354518897720))
  • TreeLeaf 是双多态连接表
  • 这应该在多态关联中发挥作用吗? api.rubyonrails.org/classes/ActiveRecord/…
【解决方案2】:

感谢克里斯展示这个想法。但我需要做一些改变才能完成这项工作。 Chris 例子的问题是如果我调用person_connections 方法会产生错误的查询。

Person.find(720).person_connections

生成此 SQL

SELECT  "people".* FROM "people"
INNER JOIN "connection_bindings"
  ON "people"."id" = "connection_bindings"."connect_to_id"
WHERE "connection_bindings"."person_id" = 720
  AND "connection_bindings"."connect_to_type" = 'Person'

person_id 列应该是 connect_from_id。所以我需要将:as =&gt; :connect_from 选项添加到has_many :connection_bindings 以显示ActiveRecord 它是一个多态关联。

has_many :connection_bindings, :as => :connect_from
has_many :person_connections,  :through => :connection_bindings,
  :source => :connect_to, source_type: 'Person'
has_many :company_connections, :through => :connection_bindings,
  :source => :connect_to, source_type: 'Company'

但这还不够。我需要能够获得反向​​连接。那么如果Person @a 添加到Person @b 的连接呢?方法连接应在@a.connections@b.connections 两个方向上显示该连接。

现在我想我可以通过添加几个额外的关联和聚合方法来做到这一点。

【讨论】:

    【解决方案3】:

    您需要告诉 ActiveRecord 它正在寻找的关联列。我猜你想要以下内容:

    class Person < ActiveRecord::Base
      has_many :connection_bindings
      has_many :companies, :through => :connection_bindings
      has_many :people, :through => :connection_bindings
    end
    
    class company < ActiveRecord::Base
      has_many :connection_bindings
      has_many :companies, :through => :connection_bindings
      has_many :people, :through => :connection_bindings
    end
    

    问题是您有两个表,将 id 放在一个列中,Rails 不知道要查找哪个表。

    例如,在数据库中任何给定的 connection_binding 行上,connect_from 可以是 company_id 或 person_id,connect_to 也是如此。所以你说:'Hey Rails,加载我关联的 ConnectionBindings',它得到一行 connect_from 为 11,connect_to 为 12。但它是 Person.find(12) 还是 Company.find(12)?没办法说!

    相反,您必须向 Rails 提供更多信息:

    class Person < ActiveRecord::Base
      has_many :connection_bindings
      has_many :person_connections, :through => :connection_bindings, :source => :to_connect, :source_type => 'Person'
      has_many :company_connections, :through => :connection_bindings, :source => :to_connect, :source_type => 'Company
    
      def connections
        person_connections + company_connections
      end
    end
    

    您需要在另一端构建它(以及相关的 :from_connect),但这取决于您如何使用这些连接。应该足以让您入门。

    它比您在 Ruby 和 Rails 的神奇世界中所习惯的要多得多,但您正在尝试构建一个非常复杂的数据模式。这并不意味着这是不可能的——Rails 作为一个优秀的框架,不会阻止你做任何你真正想做的事情——但它并不常见,需要你明确一些。

    【讨论】:

    • 感谢您指出我。你的回答很有帮助。我在下一个答案中为我写下了实际的解决方案。
    • 我知道这有点陈旧,但这正是我所需要的,而且解释是一个巨大的帮助。感谢您输入原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 2015-06-22
    相关资源
    最近更新 更多