自引用Rails HABTM关联仅以一种方式工作

时间:2018-05-03 00:20:04

标签: ruby-on-rails rails-activerecord

我有文档,其中一些是相关的,关系是对称的。也就是说,我尝试根据associationjoin table的HABTM说明对此关系进行建模。

我可以为两个Document实例d1.related_documents << d2d1.related_documents可以工作并返回相关文档,但d2.related_documents会返回一个空集。

我已声明表和模型如下:

  • 文件表

    create_table :documents do |t|
      t.string :matter
      t.string :url_id, unique: true
      t.text :body
    
      t.timestamps
    end
    
  • 加入表格

    create_join_table :documents, :documents, table_name: :related_documents, id: false do |t|
      t.references :referent, foreign_key: { to_table: :documents, 
                                             primary_key: :url_id }, index: true
      t.references :reference, foreign_key: { to_table: :documents, 
                                              primary_key: :url_id }, index: true
      end
    end
    
  • 模型

    has_and_belongs_to_many :related_documents, join_table: :related_documents, 
                                                class_name: "Document", 
                                                foreign_key: :referent_id, 
                                                association_foreign_key: :reference_id
    

1 个答案:

答案 0 :(得分:1)

自我引用的habtm有点超出标准的Rails工具箱。您需要调整finder_sql或有两个关系:

has_and_belongs_to_many :related_documents, join_table: :related_documents, 
                                            class_name: "Document", 
                                            foreign_key: :referent_id, 
                                            association_foreign_key: :reference_id
has_and_belongs_to_many :referenced_documents, join_table: :related_documents, 
                                            class_name: "Document", 
                                            foreign_key: :reference_id, 
                                            association_foreign_key: :referent_id

如果需要将结果联合成一个SQL,则需要调整Finder-SQL,例如, https://gist.github.com/srpouyet/4121517

has_and_belongs_to_many :related_documents,
                          class_name: 'Document',
                          join_table: :related_documents,
                          foreign_key: :reference_id,
                          association_foreign_key: :referent_id,
                          uniq: true,
                          finder_sql: proc { 
     %(SELECT DISTINCT "documents".* FROM "documents"
       INNER JOIN "related_documents" 
         ON "documents"."id" = "related_documents"."referent_id"
       WHERE "related_documents"."reference_id" =  #{id}
       UNION
       SELECT DISTINCT "documents".* FROM "documents"
       INNER JOIN "related_documents" 
         ON "documents"."id" = "related_documents"."reference_id"
       WHERE "related_documents"."referent_id" =  #{id} 
       )}