Вы можете решить эту проблему на уровне базы данных с помощью представления, которое в любом случае будет правильным методом.
CREATE VIEW with_inverse_animal_friends (
SELECT id,
animal_id,
animal_friend_id,
created_at,
updated_at,
status_id
FROM animal_friends
UNION
SELECT id,
animal_friend_id AS animal_id,
animal_id AS animal_friend_id,
created_at,
updated_at,
status_id
FROM animal_friends
)
Если вы не хотите иметь двойные записи для друзей с отношениями в обоих случаях, вы можете сделать это:
CREATE VIEW unique_animal_friends (
SELECT MIN(id), animal_id, animal_friend_id, MIN(created_at), MAX(updated_at), MIN(status_id)
FROM
(SELECT id,
animal_id,
animal_friend_id,
created_at,
updated_at,
status_id
FROM animal_friends
UNION
SELECT id,
animal_friend_id AS animal_id,
animal_id AS animal_friend_id,
created_at,
updated_at,
status_id
FROM animal_friends) AS all_animal_friends
GROUP BY animal_id, animal_friend_id
)
Вам понадобится способ решить, какой status_id использовать, если есть два конфликтующих. Я выбрал MIN (status_id), но это, вероятно, не то, что вы хотите.
В Rails вы можете сделать это сейчас:
class Animal < ActiveRecord::Base
has_many :unique_animal_friends
has_many :friends, :through => :unique_animal_friends
end
class UniqueAnimalFriend < ActiveRecord::Base
belongs_to :animal
belongs_to :friend, :class_name => "Animal"
end
Это из моей головы и не проверено. Также вам может понадобиться некоторый плагин для обработки представлений в рельсах (например, "redhillonrails-core").