Как использовать Hotwire в Rails 7 для создания системы уведомлений в реальном времени
29 апреля 2022 г.ОТКАЗ ОТ ОТВЕТСТВЕННОСТИ
Некоторое время назад я написал здесь статью о том, как создать систему уведомлений с помощью Rails и Redis с нуля. Этот новый является быстрым обновлением того.
Если вы не понимаете, о чем я говорю, и вам интересно, как сделать то же самое без Hotwire, вот вам:
👉 Система уведомлений в реальном времени с Sidekiq, Redis и Devise в Rails 6
Rails 7 был огромным обновлением, но я не буду говорить об этом в этом посте. Hotwire официально стал частью Rails 7. Теперь вы можете взаимодействовать в реальном времени и работать над проектами SPA, даже не написав ни одной строки JS.
TL;TR
Hotwire можно понимать как зонтик/подход. Внутри этой штуки вы найдете двух маленьких мальчиков: Turbo, который заменяет TurboLinks, и Stimulus, который, по их собственным словам (https://stimulus.hotwired.dev/): * Скромный JavaScript-фреймворк для HTML. у вас уже есть * или то, что мы собираемся использовать, когда нам нужно будет слушать нажатия кнопок :p
Практика 👊
Я собираюсь использовать чистый проект, вы можете пропустить это, если хотите. Поэтому:
$ отправляет новые уведомления_with_hotwire -d=postgresql -T
-d=postgresql
указываем базу данных, которую мы собираемся использовать. По умолчанию Rails использует sqlite3.
-T
пропускает тестовые файлы.
Чтобы сделать это более реальным, давайте включим Devise и Tailwind с их библиотекой иконок, [Heroicons ] (https://github.com/bharget/heroicon):
$ bundle add devise tailwindcss-rails heroicon
Теперь нам нужно установить эти драгоценные камни...
Для tailwind и heroicons просто запустите $ rails tailwindcss:install && rails g heroicon:install
Для Devise запустите $ rails g devise:install && rails g devise User
и следуйте их примечаниям.
Я также собираюсь создать ресурс, который будет отправлять уведомления позже: $ rails g scaffold Post title body:rich_text user:references
. Не забудьте назначить пользователя при создании,
``рубин
before_action :authenticate_user!, кроме: [ :index, :show ]
деф создать
@post = current_user.posts.new(post_params)
И, конечно же, укажите отношение к модели User с помощью:
``рубин
has_many: сообщения
Наконец, давайте перейдем к тому, что вы ищете 😉
Как создавать уведомления
Я хочу создавать уведомления для разных ресурсов, таких как посты, комментарии или лайки. Для этого я использую полиморфную ссылку. Если вы не знакомы с ним, прочитайте об этом здесь.
$ rails g model Элемент уведомления: ссылки {полиморфный} пользователь: просмотренные ссылки: логическое значение
Просто добавьте значение по умолчанию для поля просмотра при миграции:
``рубин
t.boolean: просмотрено, ноль: ложь, по умолчанию: ложь
Создайте базовую навигацию и поместите на нее значок счетчика уведомлений, например:
``рубин
<%= link_tonotifications_path, class: "bg-gray-800 p-1 rounded-full text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring -offset-grey-800 focus:ring-white" сделать %>
Просмотреть уведомления
<%= heroicon "звонок", вариант: :outline, варианты: { class: "h-6 w-6" } %>
<%= идентификатор tag.div: :notifications_count do %>
<%= отображать "уведомления/количество", количество: current_user.unviewed_notifications_count %>
<% конец%>
<% конец%>
Вы можете заметить, что unviewed_notifications_count не существует в нашей модели User, поэтому давайте определим это как метод класса в user.rb
:
``рубин
has_many: уведомления
определение unviewed_notifications_count
self.notifications.unviewed.count
конец
А партиал app/views/notifications/_count нужен для Turbo. Объясню это ниже.
``рубин
<%= идентификатор tag.div: :notifications_count do %>
<%, если количество > 0 %>
<%= количество> 9 ? "+9": количество %>
<% конец%>
<% конец%>
Вот что касается всей статьи (notification.rb
). Турбо действия. Давайте возьмем первый обратный вызов, чтобы объяснить, что происходит.
- broadcast: теперь Turbo обрабатывает то, что мы построили на предыдущей статье. TD;TR: ApplicationCable для установления соединения между пользователем и сервером, создания и отправки заданий в фоновый режим для выполнения асинхронно с Redis.
- добавлять/заменять/удалять: простые действия JS
- to: цель (также известная как поток). В этом случае я устанавливаю соединение с конкретным подписанным пользователем.
- target: простой элемент HTML (или turbo_frame) для выполнения действия JS.
``рубин
область видимости: непросмотрено, -> {где (просмотрено: ложь) }
default_scope { последний }
after_create_commit сделать
Broadcast_prepend_to "broadcast_to_user_#{self.user_id}",
цель: :уведомления
конец
after_update_commit сделать
Broadcast_replace_to "broadcast_to_user_#{self.user_id}",
цель: я
конец
after_destroy_commit сделать
Broadcast_remove_to "broadcast_to_user_#{self.user_id}",
цель: :уведомления
конец
after_commit сделать
Broadcast_replace_to "broadcast_to_user_#{self.user_id}",
цель: "количество_уведомлений",
частично: "уведомления/количество",
местные жители: {количество: self.user.unviewed_notifications_count}
конец
конец
Да, последней области также не существовало, мне нравится определять это в application_record.rb
.
``рубин
область действия: последняя, -> { заказ ("создано_в DESC") }
В application.html.erb
создайте поток, который позволяет предыдущему сниппету «разговаривать» с подписанным пользователем (без этого все получают все уведомления 😛)
``рубин
<% если user_signed_in? %>
<%= turbo_stream_from dom_id(current_user, :broadcast_to) %>
<% конец%>
Теперь давайте поместим информацию, связанную с уведомлениями, в файл беспокойства/notificable.rb.
- included добавит туда, где мы импортируем эту проблему. Он устанавливает отношения и имеет простой обратный вызов, который запускается, когда мы создаем новый объект ресурса (в данном случае post).
- Если у этой модели ресурсов есть метод user_ids, он создаст уведомления для этого пользователя.
``рубин
модуль
расширить ActiveSupport::Concern
включено делать
has_many :уведомления, как: :item, зависимые: :destroy
after_create_commit :send_notifications_to_users
конец
защита send_notifications_to_users
если self.respond_to? :user_ids
self.user_ids&.each сделать |user_id|
Notification.create user_id: user_id, элемент: self
конец
конец
конец
конец
Итак, когда мы хотим создать уведомления для нового ресурса, нам просто нужно включить эту проблему в нашу модель ресурсов, в данном случае post.rb
``рубин
включить уведомление
определение user_ids
User.where.not(id: self.user_id).ids
конец
Наконец, чтобы отобразить уведомления в пользовательском интерфейсе нашего приложения, давайте ответим на путь /notifications в файле notifications_controller.rb.
``рубин
класс NotificationsController < ApplicationController
before_action :authenticate_user!
индекс защиты
@notifications = текущий_пользователь.уведомления
@notifications.update(просмотрено: правда)
конец
конец
Не забудьте сообщить контроллеру об этом новом пути в config/routes.rb.
``рубин
ресурсы :уведомления, только: [ :index ]
Вот и все. Индекс уведомлений :)
представления/уведомления/index.html.erb
``рубин
Уведомления
<%= визуализировать @уведомления %>
Предыдущий render @notifications
будет искать партиал views/notifications/_notification.html.erb
.
И мне нравится рендерить здесь новый партиал, так как у нас полиморфное отношение.
```эрб
<%= render "notifications/#{notification.item_type.downcase}", уведомление: уведомление %>
Этот предыдущий рендеринг
будет искать views/notifications/_post.html.erb
(в данном случае). Если вы создаете уведомления, скажем, для лайков, вам нужно создать новый партиал с именем _like
. И настройте уведомление для этого нового ресурса.
```эрб
<%= уведомление.item.user.email %> только что опубликовал:
<%= ссылка_на уведомление.элемент.заголовок, уведомление.элемент, класс: "подчеркивание шрифта" %>
Вот [репозиторий] (https://github.com/matias-carpintini/notifications-with-hotwire) со всем :)
О, и я создаю доску объявлений для разработчиков, которые хотят работать удаленно. Уже есть пара предложений о работе для разработчиков Rails, если вы ищете работу, [проверьте это] (https://workby.io).
Пока.
Также опубликовано здесь
- Главное фото Johannes Plenio на Unsplash*
Оригинал