Я работаю над приложением, которое моделирует дружбу между пользователями.
class User
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
end
class Friendship
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
end
Когда два пользователя становятся друзьями, создаются два экземпляра класса дружбы, по одному для каждого направления дружбы. Это необходимо, потому что в каждом направлении могут быть установлены разные разрешения, а также для простоты поиска, поэтому мы всегда ищем по user_id без создания второго индекса и необходимости дублировать поиск.
Можно ли с помощью либо находки, либо именованного прицела подтянуть друга вместе с встречной дружбой? Я хотел бы сделать это, потому что я позволяю пользователям редактировать разрешения на дружбу, которые хранятся в их собственной ветви дружбы, и поэтому, когда я показываю информацию о друге пользователю, мне нужно проверить противоположную ногу, чтобы увидеть как устанавливаются разрешения. (Кроме того, кажется ли это логичным способом сделать что-то? Либо вы сохраняете в противоположную сторону, либо вам нужно консультироваться с противоположной стороной перед отображением, и то, и другое неприятно.)
Мне удалось создать пакет SQL, который выполняет эту работу:
def self.secure_friends(user_id)
User.find_by_sql("SELECT u.*, cf.permissions
FROM users u
INNER JOIN friendships f ON u.id = f.friend_id
INNER JOIN friendships cf ON u.id = cf.user_id AND cf.friend_id = #{user_id}
WHERE ((f.user_id = #{user_id}) AND (f.status = #{Friendship::FULL}))")
end
Функция возвращает все имена и идентификаторы друзей пользователя вместе с разрешениями. Однако это действительно не кажется идеальным и означает, что мне нужно получить доступ к разрешениям, вызвав friend.permissions, где разрешения на самом деле не являются членом друга, а просто объединены как атрибут с помощью find_by_sql. В общем, я бы предпочел сделать это с помощью named_scope или вызова find, но, к сожалению, каждая моя попытка использовать этот подход приводила к ошибкам, поскольку Rails задыхается от того, что одна и та же таблица присоединения Friendship запрос дважды.