Ruby on Rails: возможно ли: включить другую часть круглого стола соединения? - PullRequest
2 голосов
/ 05 марта 2010

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

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

1 Ответ

2 голосов
/ 16 июня 2010

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

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

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!}
...