Как использовать Hotwire в Rails 7 для создания системы уведомлений в реальном времени

Как использовать 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). Турбо действия. Давайте возьмем первый обратный вызов, чтобы объяснить, что происходит.


  1. broadcast: теперь Turbo обрабатывает то, что мы построили на предыдущей статье. TD;TR: ApplicationCable для установления соединения между пользователем и сервером, создания и отправки заданий в фоновый режим для выполнения асинхронно с Redis.

  1. добавлять/заменять/удалять: простые действия JS

  1. to: цель (также известная как поток). В этом случае я устанавливаю соединение с конкретным подписанным пользователем.

  1. 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.


  1. included добавит туда, где мы импортируем эту проблему. Он устанавливает отношения и имеет простой обратный вызов, который запускается, когда мы создаем новый объект ресурса (в данном случае post).

  1. Если у этой модели ресурсов есть метод 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).


    Пока.


    Также опубликовано здесь




    Оригинал
    PREVIOUS ARTICLE
    NEXT ARTICLE