Как реализовать модель дружбы в Rails 3 для приложения для социальных сетей?
В настоящее время я работаю над небольшим приложением для социальных сетей и сейчас пытаюсь создать модель, которая представляет дружбу между пользователями. Это то, что я придумал до сих пор:
class User < ActiveRecord::Base
# ...
has_many :friendships
has_many :friends, :through => :friendships
end
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :friend, :class_name => 'User'
end
У моей модели дружбы есть поле, подтвержденное как логическое, которое я хотел бы использовать, чтобы определить дружбу как ожидающую или подтвержденную.
Как я могу получить доступ ко всем ожидающим запросам для определенного пользователя? Могу ли я как-то определить это с помощью метода области действия Rails? Что-то вроде
current_user.friendships.requests # => [Friendship, Friendship, ...]
было бы замечательно.
Как я могу сделать эту ассоциацию двунаправленной? Можно ли просто добавить еще одну дружбу после подтверждения запроса о дружбе, чтобы моя таблица дружбы выглядела примерно так:
| user_id | friend_id | confirmed |
-----------------------------------
| 1 | 2 | true |
| 2 | 1 | true |
5 ответов
Чтобы получить доступ ко всем ожидающим дружеским отношениям, вы можете использовать ассоциацию:
has_many :pending_friends,
:through => :friendships,
:source => :friend,
:conditions => "confirmed = 0" # assuming 0 means 'pending'
Чтобы сделать дружбу двунаправленной, вы можете заменить свой столбец с логическим подтверждением на столбец состояния строки, который имеет одно из следующих трех значений: "в ожидании", "запрошено" и "принято" (необязательно "отклонено"). Это поможет отследить, кто сделал запрос на дружбу.
Когда отправляется запрос о дружбе (скажем, из Foo в Bar), вы создаете две записи о дружбе (заключенные в транзакцию): одну запрошенную и одну ожидающую отражения, соответственно. у этого бара запрошенная дружба с Фу, а у Фу - ожидающая дружба с Баром.
def self.request(user, friend)
unless user == friend or Friendship.exists?(user, friend)
transaction do
create(:user => user, :friend => friend, :status => 'pending')
create(:user => friend, :friend => user, :status => 'requested')
end
end
end
Когда дружба принята (например, Бар), обе записи дружбы устанавливаются как принятые.
def self.accept(user, friend)
transaction do
accepted_at = Time.now
accept_one_side(user, friend, accepted_at)
accept_one_side(friend, user, accepted_at)
end
end
def self.accept_one_side(user, friend, accepted_at)
request = find_by_user_id_and_friend_id(user, friend)
request.status = 'accepted'
request.accepted_at = accepted_at
request.save!
end
Это в значительной степени освещено в главе 14 книги "Железнодорожное пространство" Михаэля Хартла и Аврелия Прохазки. Вот исходный код, который должен помочь вам усовершенствовать ваше решение.
Конечная ссылка:
http://railscasts.com/episodes/163-self-referential-association
Короткий ответ - да. Просто сделайте еще одну запись дружбы, чтобы представлять двунаправленную ассоциацию.
Я написал гем под названием has_friendship для такого рода проблем. Все, что вам нужно сделать, это зайти в has_friendship
в вашей модели, и все ассоциации и методы будут учтены.
Надеюсь это поможет!
Прочтите этот урок, иллюстрирующий модель отношений в Rails Tutorials. Это должно быть именно то, что вы ищете.
Я рекомендую вам книгу RailsSpace: Создание сайта социальной сети. Это ясно объясняет, как реализовать модель дружбы. Хотя это не распространяется на другие формы отношений, но вполне применимо для вашей проблемы.