Это мой последний проект в школе Flatiron. В этом проекте не было ограничений. Единственными требованиями было использование Rails, React и Redux. Я решил сделать приложение, в котором люди могут общаться в приватных чатах, предлагать, куда пойти, и голосовать за лучших. Все эти функции должны быть «живыми», что означает мгновенный ответ всем участникам чата.

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

Я реализовал систему аутентификации, используя JWT с истекающим сроком действия (Javascript Web Token). Когда пользователи входят в систему, они получают уникальные токены, которые их представляют. JWT состоит из 3 частей: заголовка, полезной нагрузки и подписи для подтверждения подлинности этого токена. В моем случае я сохраняю идентификатор пользователя и псевдоним в качестве полезной нагрузки (обратите внимание, что эта информация общедоступна и может использоваться где угодно). После получения этого JWT на стороне клиента он должен включать этот токен в каждый запрос в заголовке авторизации. Таким образом, сервер может определить пользователя.

Когда пользователи регистрируются, они могут загружать свои аватары (с предварительным просмотром на странице). Я реализовал это с использованием Amazon S3 хранилища (как в проекте Study Helper).

Основная часть: пользователи могут создавать приватные чаты и приглашать в них других пользователей (гостей). Каждый чат состоит из 3 частей: сам чат, управление предложениями и голосование за них. Таким образом, у каждого чата есть один владелец и много гостей (отношения «многие ко многим»). Каждый участник может создавать сообщения, предложения и голосовать. Для реализации механизма голосования я использовал activerecord_reputation_system gem. Это действительно полезно.

А теперь самое интересное: живые чаты. Я думаю, что лучший способ реализовать это — использовать Websockets. Rails (начиная с Rails 5) создала библиотеку ActionCable с полным стеком (помимо того, что интерфейсная часть доступна отдельно в npm). В нем реализованы все трудоемкие концепции веб-сокетов, так что мы можем легко приступить к разработке собственных идей. Основная идея веб-сокетов заключается в создании соединений между клиентами и сервером. После создания этих подключений сервер может отправлять (транслировать) данные всем абонентам без запросов. В реализации ActionCable каждый клиент может иметь только одно соединение (кабель) и несколько каналов. Клиентский код должен делать запрос на создание кабеля, и он может подписываться на разные каналы.

В Chat Vote Go у меня есть 2 типа каналов: сообщения чатов и предложения чатов (для каждого чата). Таким образом, клиенты могут самостоятельно создавать сообщения и предложения в чате. Система голосования не нуждается в третьем канале. С этим справляется канал предложений: когда клиенты отправляют запросы на голосование, этот канал выполняет необходимую работу и транслирует два предложения: проголосовавшее и не проголосовавшее.

Для создания соединения серверу необходимо аутентифицировать и авторизовать пользователя. Поэтому ему нужен JWT. И вот проблема: веб-сокеты не позволяют использовать пользовательские заголовки, такие как авторизация! Пока что я принял не лучшее решение: отправить запросом в URL. Это не совсем безопасно. Так что я решу эту проблему позже.

Это была самая сложная часть! Было действительно сложно правильно понять все концепции Redux. Для этого я посмотрел все 30 + 27 видео (даже несколько раз) Дэна Абрамова (создателя Redux). Они чрезвычайно полезны. Поэтому я попытался собрать Idiomatic Redux. Однако мое приложение не является чисто Redux: я не храню ВСЕ данные в магазине. Некоторые переменные пользовательского интерфейса и входные значения формы хранятся в локальных состояниях компонентов. Думаю, это правильное решение: Store должен заботиться только об общих (между компонентами) и важных данных.

Я стараюсь нормализовать данные с сервера, чтобы эффективно использовать их в магазине Redux. Это означает, например, что объект чата не содержит объект массива сообщений. Он содержит массив идентификаторов сообщений. Сообщение является независимой сущностью (подумайте об этом как о базе данных), поэтому оно хранится отдельно от чатов в виде { id: messageData }:

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

Итак, у меня в магазине 6 основных сущностей:

  • auth (содержит информацию об аутентификации и ActionCable)
  • пользователи (содержит нормализованную информацию о пользователях)
  • чаты
  • Сообщения
  • предложения
  • flashСообщения

В моем приложении вы можете выбрать чат (или пользователя, если вы ищете пользователей) из списка на боковой панели. В магазине Redux ему соответствует объект с базовой информацией о пользователях (id, title). Когда вы нажимаете на определенный чат, приложение отправляет запрос на сервер для получения полной информации. Это приводит к обновлению определенной записи в объекте чатов. Если вы выйдете с этой страницы, а затем вернетесь, вы мгновенно получите информацию о чате, потому что она кэшируется. Однако приложение по-прежнему делает запрос, если что-то изменится на сервере.

Для визуализации результатов голосования я использую библиотеку Recharts (на основе D3) для отображения круговой диаграммы.

Другой важной частью Idiomatic Redux является использование селекторов. Ваше приложение не должно знать о форме вашего магазина. Это работа редукторов. Таким образом, редукторы должны иметь так называемые селекторы или геттеры (функции) для получения определенных срезов состояния или выполнения некоторых вычислений перед возвратом. С помощью селекторов вы можете легко изменить форму вашего магазина, не касаясь компонентов.

Когда пользователь входит в систему, интерфейсное приложение отправляет запрос на установление соединения Websocket с сервером.

После этого, если пользователь посещает определенную страницу чата, приложение делает запрос на подписку на 2 канала: сообщения чата и предложения. Если он/она меняет чат, приложение отписывается от текущего чата и подписывается на новый чат.

Также хочу отметить, что пользователи могут создавать предложения в двух режимах: пользовательское предложение и поиск предложений. Я реализовал поисковые подсказки и получение подробной информации о них с помощью Google Places API.

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

Это значит, что я почти закончил школу Flatiron! Это было действительно захватывающе, захватывающе и тяжело. Флэтайрон — замечательная школа. Мне даже немного грустно, что он подходит к концу. Но я должен двигаться дальше и начать свою карьеру! Надеюсь, это подарит мне еще больше эмоций :)

Гитхаб-интерфейс

Гитхаб Бэкэнд

"Веб-сайт"

Первоначально опубликовано на сайте aleksandr-rogachev-blog.com 26 мая 2017 г.