Погружение в драгоценный камень has_friendship Ruby

Социальные сети изменили способ взаимодействия людей с веб-приложениями.

Возможность общаться с другими пользователями и общаться делает приложение приятным, интересным и популярным - так почему же не все приложения используют эту функцию?

Хотя есть много причин, по которым разработчики предпочли бы отказаться от «функциональности дружбы», одним из основных факторов является сложность.

Дружба может быть сложной задачей, но вы можете решить эту проблему так же, как и любую другую проблему в программировании, - познакомившись с ней.

В этих примерах будет использоваться Ruby on Rails с отношениями Active Record, но другие технологии могут использовать аналогичные решения.

Быстрое и эффективное решение

Работая над недавним проектом Rails, я наткнулся на великолепный гем Ruby "has_friendship, созданный Сунг Вон Чо и его командой разработчиков.

Давайте погрузимся в установление дружеских отношений с этим драгоценным камнем.

  1. Создайте User класс с атрибутом has_friendship.
  2. Как и все драгоценные камни, добавьте gem “has_friendship” в свой Gemfile и запустите bundle.
  3. Установите и запустите предоставленные миграции Active Record.
$ rails has_friendship_engine:install:migrations
$ rails db:migrate

С помощью этой простой настройки “has_friendship” создал сложные самореференциальные таблицы соединений и предоставил вам множество отличных методов для доступа к ним.

Пользователи сгруппированы в четыре категории, соответствующие друг другу:

  • requested_friends
  • pending_friends
  • blocked_friends
  • friends

Используя этот драгоценный камень, мы также можем запрограммировать метод фильтрации, чтобы найти всех пользователей с нулевой ассоциацией.

def strangers
   users = []
   User.all.each do |user|
      if(self.friends_with?(user) != true && self != user &&       self.friends.include?(user) != true && self.pending_friends.include?(user) != true && self.requested_friends.include?(user) != true)
      users << user
      end
   end
   users
end

Это позволяет вызвать @user.strangers и получить массив пользователей, которые никак не связаны (и исключить экземпляр пользователя, для которого мы вызвали метод).

Однако, если вы разрабатываете приложение для работы с большим количеством пользователей, вы можете создать более сложные методы фильтрации, чтобы сократить время вычислений.

Наш следующий шаг в этом захватывающем приключении - создать FriendsController, который может динамически обрабатывать эти отношения для текущего пользователя нашего приложения.

  • Ваше действие index может отображать всех текущих пользователей requested_friends, pending_friends и friends.
  • Ваше create действие может включать @user.friend_request(User.find_by(id: params[:id])).
  • Ваше destroy действие может включать @user.remove_friend(User.find_by(id: params[:id])).

Я добавил два настраиваемых действия, add и reject, чтобы также легко запускать методы accept_request и decline_request.

Имея эти действия контроллера, вы готовы программировать полнофункциональную платформу социальных сетей с использованием Ruby on Rails!

Надеюсь, что в этом примере вы также увидите удивительную силу драгоценных камней Ruby и невероятную ценность программного обеспечения с открытым исходным кодом.

Более глубокий уровень понимания

Как и в случае с любой другой темой программирования, все может стать пугающим, если вы спрыгнете с уровня абстракции.

Однако высокая сложность приносит большую награду, и программисты, желающие погрузиться в абстракцию, получат обширный контроль над своим проектом.

Основным элементом, который делает возможным поведение в социальных сетях посредством активной записи, являются самореференциальные отношения.

Чтобы имитировать поведение, которое мы достигли с гемом “has_friendship”, мы создадим две миграции.

def change
   create_table :friendships do |t|
      t.references :friender, foreign_key: false
      t.references :friended, foreign_key: false
end
def change
   create_table :friend_requests do |t|
      t.references :requester, foreign_key: false
      t.references :requested, foreign_key: false
end

Я устанавливаю foreign_key на false для простоты этого примера. Если вы хотите установить правильные отношения внешнего ключа, см. Верхний ответ в этом сообщении о переполнении стека.

Затем мы можем создать две соответствующие модели.

class Friendship < ApplicationRecord
  belongs_to :friender, class_name: 'User'
  belongs_to :friended, class_name: 'User'
end
class FriendRequest < ApplicationRecord
  belongs_to :requester, class_name: 'User'
  belongs_to :requested, class_name: 'User'
end

В этих моделях вы сообщаете Active Record, что все метки, такие как :requester и :requested, относятся к идентификаторам пользователей.

После установления этих отношений у нас есть последний шаг в начальной настройке.

class User < ApplicationRecord
   has_many :friended_users, foreign_key: :friended_id, class_name: 'Friendship'
   has_many :frienders, through: :friended_users
has_many :friender_users, foreign_key: :friender_id, class_name: 'Friendship'
   has_many :friendeds, through: :friender_users
has_many :requested_users, foreign_key: :requested_id, class_name: 'FriendRequest'
   has_many :requesters, through: :requested_users
has_many :requester_users, foreign_key: :requester_id, class_name: 'FriendRequest'
   has_many :requesteds, through: :requester_users
end

В этом примере я использовал абсурдную схему именования, чтобы подчеркнуть важность согласованности с таблицами соединений.

Не обязательно копировать этот синтаксис в точности, но ошибки из-за неправильного именования в таблицах соединения являются обычным явлением.

Поскольку наш код становится все более плотным, давайте еще раз проверим наше понимание:

  1. У нас есть две таблицы соединения: friendships, и friend_requests.
  2. Эти таблицы используют внешние ключи для установления отношений, но мы сказали им во всех случаях искать user_ids.
  3. Когда один пользователь инициирует отношения, противоположные отношения создаются с другим пользователем.

Пример:

ted = User.create(name: "Ted")
amy = User.create(name: "Amy")
ted.requesteds << amy
                           ActiveRecord magic
amy.requesters.first.name
#=> "Ted"

После того, как обе эти связи будут правильно настроены, вы получите доступ к приятным методам Active Record, таким как:

Friendship.new(friender: ted, friended: amy)
#=> <Friendship id: 1, friender_id: 1, friended_id: 2>

Поздравляем! Если вы можете запустить оба этих блока кода, вы успешно создали две самореференциальные таблицы соединений для обработки запросов на добавление в друзья и дружбы.

Теперь дело за вами, программистом, - использовать эти инструменты во благо. Поначалу может быть сложно понять логику принятия и отрицания друга, но вы не первый, кто проходит через эту борьбу.

Вот два примера методов: friend_request и accept_request.

...in User model
def friend_request(user)
   FriendRequest.create(requester: self, requested: user)
end
def accept_request(user)
   FriendRequest.find_by(requester: self, requested: user).destroy
   Friendship.create(friender: self, friended: user)
end

И точно так же у вас есть полностью настраиваемая платформа социальных сетей, установленная в вашем проекте Rails.

Несомненно, существуют более продвинутые способы установления отношений в социальных сетях для проектов Rails (как это), но понимание самореференциальных таблиц соединения всегда имеет решающее значение.

Социальные сети стали основным элементом человеческого взаимодействия.

Надеюсь, вы узнали о некоторых тонкостях управления базами данных в нашу социальную эпоху и сможете применить эти знания для создания приложений, которые помогут объединить людей.