Похоже, существует несколько способов обработки связи с несколькими внешними ключами.Каждый способ, которым я подошел к этому, имеет свои недостатки, и, поскольку я новичок в Rails, я убежден, что другие сталкивались с подобным сценарием, и я, вероятно, работаю над чем-то решенным давно.
Мой вопрос:
Каким был бы эффективный способ обработки связи с несколькими индексными ключами, при этом сохраняя все другие модификаторы sql Rails (такие как: include и т. Д.)?
Мой сценарий:
У меня есть следующая таблица (упрощенная), которая используется для соединения людей с другими людьми по ссылкам:
People
+----+-----------+
| id | name |
+----+-----------+
| 1 | Joe |
+----+-----------+
| 2 | Sally |
+----+-----------+
| 3 | Bob |
+----+-----------+
Links
+----+-----------+---------+
| id | origin_id | rcvd_id |
+----+-----------+---------+
| 1 | 2 | 1 |
+----+-----------+---------+
| 2 | 1 | 3 |
+----+-----------+---------+
| 3 | 3 | 2 |
+----+-----------+---------+
Из строки 1 приведенной выше таблицы ссылок можносм., что Person (Sally = 2) связан с другим Person (Joe = 1).
Мне легко найти все ссылки Persons, если мой внешний ключ был "origin_id".Но это только покажет людям, создающим ссылку.В моем сценарии мне нужно видеть все ссылки независимо от того, были ли они созданы или получены лицом.Например, если бы я попросил все ссылки Салли (Sally = 2), я бы хотел получить следующий результат:
Links
+----+-----------+---------+
| id | origin_id | rcvd_id |
+----+-----------+---------+
| 1 | 2 | 1 |
+----+-----------+---------+
| 3 | 3 | 2 |
+----+-----------+---------+
Следовательно, у меня есть 2 индексных ключа, оба - origin_id и rcvd_id.
Одним из способов решения этой проблемы является метод:
class Person < ActiveRecord::Base
has_many :link_origins, :class_name => "Link", :foreign_key => :origin_id, :dependent => :destroy
has_many :link_rcvds, :class_name => "Link", :foreign_key => :rcvd_id, :dependent => :destroy
def links
origin_person + rcvd_person
end
Однако это неэффективно.Например, для этого требуется собрать всю коллекцию из базы данных, и только тогда сработает метод paginate (я использую гем will_paginate), который побеждает точку, поскольку paginate должен ускорить процесс, ограничивая количество вызываемых записей.Не ограничивать записи после того, как вся коллекция уже сделана.
Также вышеизложенное не позволит мне вызвать, например, Joe.links (: first) .origin_id.name.Не совсем этот код, но это означает, что я не смог вызвать детали Person для origin_id выбранной ссылки, так как метод links не знает, что origin_id связано с таблицей People.
На данный момент наиболее работоспособным решением является: finder_sql.
class Person < ActiveRecord::Base
has_many :links, :finder_sql => 'SELECT * FROM links WHERE (links.origin_id = #{id} or links.rcvd_id = #{id})'
Это дает все ссылки, где Person_id соответствует либо Links.origin_id, либо Links.rcvd_id.
Недостатком этой опции является то, что использование: finder_sql исключает все другие модификаторы sql, так как Rails не знает, как анализировать и изменять предоставляемый вами SQL.Например, я бы не смог использовать опцию: include с: finder_sql.
Итак, сейчас я использую решение: finder_sql.Но кажется, что это может быть сделано так, что мне не нужен: finder_sql.Например, есть ли способ написать пользовательскую строку SQL, сохранив SQL-модификаторы Rails, которые предоставляет Active Record.
Есть идеи по поводу вышеизложенного?