Связи ActiveRecord для таблицы соединений, связывающей две записи одной и той же таблицы? - PullRequest
1 голос
/ 05 июня 2009

У меня есть модель персонажа и модель связи. Модель Link представляет собой ссылку от персонажа к другому персонажу. Ссылка имеет текстовый атрибут «описание». Ссылка от символа A к символу B отличается от противоположной ссылки от B к A. Символ имеет ноль или одну ссылку на другой символ. Персонаж может иметь различные ссылки на разных персонажей. Персонаж может быть связан с различными персонажами.

Я использовал связи Active Record для частичной реализации отношений между символами и моделями ссылок:

class Character 
 has_many :links # the links from the character to other characters

class Link 
 belongs_to :character # the character from which starts the link to another character

, которые дают мне полезные методы, такие как character.links (массив всех ссылок, начинающихся с этого символа) или link.character (символ, с которого начинается ссылка)

Модель связи также имеет to_character_id, который содержит идентификатор персонажа, который идет по ссылке. Таким образом, ссылка от символа A к символу B является экземпляром со следующими атрибутами:

  • character_id = идентификатор символа A
  • to_character_id = идентификатор символа B
  • description = некоторый текст

Я написал несколько дополнительных методов, таких как character.links_to (возвращает массив всех ссылок, указывающих на символ) или link.to_character (возвращает символ, на который указывает ссылка), или character.characters_who_link_to (возвращает массив других персонажей, имеющих ссылку на этого персонажа). Я также написал обратный вызов, чтобы убедиться, что при удалении символа удаляются все ссылки на этот символ (то же самое для восстановления).

Можно ли использовать дополнительные объявления отношений AR, которые бы предоставили мне такие дополнительные методы, чтобы мне не приходилось самим писать эти методы и обратные вызовы?

Agile Web Development с Rails представляет решение в разделе «Использование моделей в качестве таблиц объединения», но для таблицы объединения, объединяющей две разные таблицы. В моем случае моя таблица соединений Ссылки объединяют записи одной таблицы, символов.

Ответы [ 3 ]

3 голосов
/ 05 июня 2009

has_and_belongs_to_many больше не используется; Я бы использовал has_many :through вместо.

class Character < ActiveRecord::Base
   has_many :links, :dependent => destroy
   has_many :characters, :through => :links 

   has_many :source_links, :class_name => "Link", 
     :foreign_key => "to_character_id", :dependent => :destroy
   has_many :source_characters, :class_name => "Character", 
     :through => :destination_links
 end

 class Link < ActiveRecord::Base
   belongs_to :character
   belongs_to :source_character, :class_name => "Character", 
    :foreign_key => "to_character_id"
 end

Обратите внимание на опции :dependent => :destroy - они будут удалять ссылки при удалении персонажа. Называние правильное - с точки зрения персонажа, source_links - это ссылки на этого символа Так что теперь вы можете сделать:

@character.characters # characters I link to
@character.links # links I have to other characters
@character.source_characters # characters that link to me
@character.source_links # links other characters have to me
2 голосов
/ 05 июня 2009

Я думаю, вы хотите что-то вроде следующего:

 class Character < ActiveRecord::Base
   has_many :outbound_links, :class_name => "Link", :foreign_key => "from_character_id"
   has_many :inbound_links, :class_name => "Link", :foreign_key => "to_character_id"
 end

 class Link < ActiveRecord::Base
   belongs_to :from_character, :class_name => "Character", :foreign_key => "from_character_id"
   belongs_to :to_character, :class_name => "Character", :foreign_key => "to_character_id"
 end

Вы можете прочитать о всех ваших параметрах ассоциаций ActiveRecord на http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

0 голосов
/ 05 июня 2009

Я думаю, что вы на самом деле собираетесь использовать самореферентные отношения HABTM с использованием таблицы соединений

так что если у вас есть стол для соединения

create_table :character_links do |t|
   t.integer :character_id
   t.integer :linked_character_id
   t.timestamps #if you want to know when the relationship was created
end

Тогда у вас будет

class Characters < ActiveRecord::Base
   has_and_belongs_to_many :linked_characters, 
      :class_name => "Characters", 
      :join_table => :character_links, 
      :foreign_key => "character_id", 
      :associated_foreign_key => "linked_character_id"

если вам нужны исходящие и входящие ссылки, вы можете просто сделать

class Characters < ActiveRecord::Base
   has_and_belongs_to_many :outgoing_links, 
      :class_name => "Characters", 
      :join_table => :character_links, 
      :foreign_key => "character_id", 
      :associated_foreign_key => "linked_character_id"

   has_and_belongs_to_many :incoming_links, 
      :class_name => "Characters", 
      :join_table => :character_links, 
      :foreign_key => "linked_character_id", 
      :associated_foreign_key => "character_id"

Только что поменял иностранный ключ и связанный_файл_ключа

Это исключает необходимость иметь отдельную модель ссылок

Это воздушный код (не тестировался)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...