Ruby on Rails: возможно ли :включить другую часть таблицы с круглым соединением?

Я работаю над приложением, которое моделирует дружбу между пользователями.

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 запрос дважды.


person William Jones    schedule 05.03.2010    source источник


Ответы (1)


Я не уверен, сколько вы хотите сделать и сколько вы позволите сделать плагину, но я с большим успехом использовал этот плагин has_many_friends: плагин has_many_friends на Github

Вы можете посмотреть на источник и вдохновиться... Просто нужна модель Friendship, в которой есть такие вещи, как:

belongs_to :friendshipped_by_me,   :foreign_key => "user_id",   :class_name => "User"
belongs_to :friendshipped_for_me,  :foreign_key => "friend_id", :class_name => "User"

а затем позже, в вашем пользовательском классе, есть:

has_many :friends_by_me,
         :through => :friendships_by_me,
         :source => :friendshipped_for_me

Или просто

/приложение/модели/пользователь

has_many_friends

Потом:

@current_user.friends.each{|friend| friend.annoy!}
person Jesse Wolgamott    schedule 15.06.2010