Самореферентная ассоциация Rails HABTM работает только в одну сторону - PullRequest
0 голосов
/ 03 мая 2018

У меня есть документы, и некоторые из них связаны, а отношение симметрично . Тем не менее, я попытался смоделировать это отношение в соответствии с инструкциями HABTM для ассоциации и таблицы соединений .

Я могу сделать d1.related_documents << d2 для двух экземпляров Document. d1.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 голосов
/ 03 мая 2018

Самоссылочный habtm находится немного за пределами стандартного набора инструментов Rails. Вам нужно настроить finder_sql или иметь 2 отношения:

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} 
       )}
...