Hotwire и Rails, урок #5 | Слушаем подписки TurboStream, условный рендер, ленивые фреймы, Stimulus

  Рет қаралды 1,127

Ilya Krukowski

Ilya Krukowski

Күн бұрын

Пікірлер: 57
@Александр-е9ь8ь
@Александр-е9ь8ь 2 ай бұрын
С возвращением! )
@mdezh
@mdezh Жыл бұрын
Спасибо за интересное видео. Вообще, рад, что набрел этот канал: сейчас в процессе свича на рельсы, и тут нахожу заметно больше "продвинутых", не банальных моментов в сравнении с многими другими авторами.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Спасибо на добром слове!
@serhiin1154
@serhiin1154 Жыл бұрын
Спасибо за видео по руби и рельсам! Как предложение темы для следующих видео - разработка API, то есть чисто backend с покрытием тестами.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Да это давно хочется сделать, но вот всё никак - какие-то другие темы всплывают постоянно
@anthonybaranoff
@anthonybaranoff Жыл бұрын
@@IlyaBodrovKrukowskiвсе еще ждем:)
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@anthonybaranoff Да, я понимаю. Но, как писал в телеграме, я потихоньку отхожу от Rails, честно говоря. Не знаю, как оно будет дальше, но пока есть интерес другие темы рассматривать
@Aluston1783
@Aluston1783 10 ай бұрын
Большое спасибо! очень полезное видео!
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski 10 ай бұрын
@dpogrebnoy
@dpogrebnoy Жыл бұрын
Спасибо за видео! Буду ждать новое =)
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Постараюсь что-нибудь ещё по теме придумать
@volodya_in_IT
@volodya_in_IT Жыл бұрын
Спасибо за видео, но у меня вопрос, получается, что в связке турбо и стимулус мы имеем "брешь" в том, что если в html просто сделать подмену user_id то будет рендериться не та информация, которую мы хотели показывать пользотелю? И пользователь может увидеть лишнее, не нужные ему поля - как в таком случае бороться? Как то хэшировать user_id или как то скрытно лучше передавать данные?
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
там не просто user_id (если говорить о фрейме), но в теории возможна ситуация, что кто-то подделает идентификатор (там шифрованный он). Впрочем, как и возможна ситуация, что кто-то подделает сессию или подберёт пароль
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Друзья, ПАРУ ВАЖНЫХ МОМЕНТОВ, ОБЯЗАТЕЛЬНО ПРОЧИТАЙТЕ!!! Во-первых, для дополнительной безопасности в хуке subscribed (на сервере) имеет смысл сравнивать room_id из params (который шлёт юзер через data) и из названия самой подписки. Просто чтобы юзер не пытался подделать название канала (оно там зашифровано, но всё-таки) и читать сообщения из другой комнаты. Вот вариант решения github.com/bodrovis-learning/HotwireSeries/commit/9833739299e11c2387c6694f3616e3af04e0de33#diff-a05199c148cac09231f0d34388c4b35b946381dd72b59c184eaaca9b8771be99L8 Во-вторых, в комментариях предлагаются и другие решения - обязательно посмотрите, интересно. Разница в том, что в предлагаемых решениях вводятся дополнительные каналы подписки, а в моём демо канал 1 на всех, включая гостей. В разных случаях могут подойти, конечно, разные реализации - универсального подхода на все случаи жизни нет. Так, действительно, можно сделать "персональные" каналы для разных юзеров и им уже отправлять разную разметку - скажем, тому, кто лайкнул придёт разметка с кнопкой "снять лайк". Но тут надо помнить, что может произойти ситуация, что у вас очень много юзеров и каждому по факту будет рендерится персонально представление, что может быть не очень оптимально.
@ledockol
@ledockol Жыл бұрын
Вообще-то уникальные каналы в связке с общими решают много задач. Мы можем даже флешсообщения или сообщения об ошибках броадкастить только нужному пользователю. У меня очень активно используется персонализированый канал для отправки броадкастом уведомлений о выполнении фоновых задач, получения других уведомлений (follow, like, favorite) - наряду с пуш уведомлениями это довольно удобно.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@ledockol Не спорю, зачастую бывает полезно
@azizdevfull
@azizdevfull Жыл бұрын
amazing : )
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@alexanonym1584
@alexanonym1584 9 ай бұрын
22-09 Что означает. %i[create show update ] ?
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski 9 ай бұрын
ну это можно было бы и погуглить. Создаём массив из символов
@mdezh
@mdezh Жыл бұрын
Пересмотрел часть про запрет подписки, и возник такой вопрос. В какой момент клиент пытается подписаться: когда тег, сформированный из хелпера turbo_stream_from присоединяется к DOM? А если я его добавлю из консоли браузера через js, тоже сработает? Я к тому, что в этом случае злоумышленнику, похоже, ничего не мешает добавить в DOM такой же тег с заменой data_room_id на id какой-нибудь другой комнаты, доступ к которой ему разрешен - и подписаться на запрещенный для него броадкаст. Или я что-то неверно понял?
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Подписка идёт так. На странице есть JS, который мониторит наличие тэга turbo. Появился тэг - JS отправил запрос на сервер, что надо подписаться. Если мы не запрещаем подписку явно в соответствующем хуке, то можно слушать обновления этого канала. Поэтому в теории да - хакер может попытаться подобрать правильный идентификатор (тк там, если посмотреть сформированную разметку, то имя канала превращается в абракадабру зашифрованную). Именно поэтому надо делать проверку в хуке подписки уже на сервере discuss.hotwired.dev/t/turbo-stream-security/3418/3
@mdezh
@mdezh Жыл бұрын
@@IlyaBodrovKrukowski Да, я об этом же - если уж у хакера каким-то образом есть идентификатор нужного канала, то проверка data_room_id не спасает, если у этого хакера есть хоть одна "разрешенная" комната (например, личная, которую он сам создал). За ссылку спасибо, сейчас гляну.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@mdezh Ну тут суть такая, что мы смотрим current_user ещё, вытаскивая id юзера из куки или сессии. Подделать сессию, если она правильно защищена, или зашифрованный куки - это малореальная история. Поэтому комбинацию user_id и комнаты и даёт защиту от всяких умников
@mdezh
@mdezh Жыл бұрын
@@IlyaBodrovKrukowski Подделывать куки не надо. Я имею в виду следующее. Допустим, я хакер. Я регистрируюсь в чате и получаю доступ в какую-то комнату X (создаю свою, если приложение позволяет). Затем я каким-то образом узнаю зашифрованный идентификатор канала броадкаста комнаты Y, которая для меня запретна (мы предполагаем такую возможность, иначе дополнительная защита просто не нужна). Дальше я открываю страницу своей "разрешенной" комнаты X и в консоли браузера удаляю тег подписки на броадкаст и добавляю новый, с зашифрованным идентификатором "запретной" комнаты Y, но с атрибутом data_room_id моей "разрешенной" комнаты X. JS видит появление тега, делает запрос на подписку. Сервер проверяет мои куки и видит, что я имею право на доступ к комнате X из data_room_id и дает добро - но сам канал-то от другой комнаты Y! Пью чай, смотрю, как на странице моей комнаты X появляются обновления из "запрещенной" комнаты Y)) Возможно, я что-то недопонял, но пока не вижу препятствий для такой атаки.
@mdezh
@mdezh Жыл бұрын
@@IlyaBodrovKrukowski Вобщем, я тут подумал, и сдается мне, нам нужен еще один data-параметр к турбо-тегу, что-то вроде data-room-digest, куда сервер будет класть хэш от room_id с секретной солью. А при проверке разрешения подписки надо будет проверять не только разрешенность комнаты из room_id для юзера из куки, но и то, что хэш room_id с солью равен data-room-digest, т.е. что room_id не был подменен хакером. Думаю, так)
@codeline9387
@codeline9387 Жыл бұрын
комментарии скрываются, вроде ничего запрещенного не писал
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
YT проказничает опять. Их алгоритмы вообще любят удалять сообщения с кодом или ссылками, этой проблеме уже года три
@codeline9387
@codeline9387 Жыл бұрын
@@IlyaBodrovKrukowski похоже на то) собственно комментарий был в том что каунт на релейшене лучше не вызывать в парашале, т.к. будет N+1, можно лентс вызывать если у нас подгрузка ассоциций тогда будет приведение к массиву без запроса в бд, но лучше посчитать все сразу через Лайки.группировка( по айди сообщения).количество, а потом уже как с хэшом работать во вьюхе
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@codeline9387 Да там просто counter cache нужен, кажется, я упомянул что-то такое. Просто его делать лень было, да и суть урока не в этом
@Sergey69ful
@Sergey69ful Жыл бұрын
а ты не разобрался с темой если юзер теряет коннект и больше 15 минут отсутствует в сети то только тогда коннекшн дропается, при то что сделав пинг пользователю то все ок? в общем сокеты с дисконнектами плохо работают в рельсах
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Тут сходу не скажу, но там могут быть действительно сложности
@Sergey69ful
@Sergey69ful Жыл бұрын
@@IlyaBodrovKrukowski у меня были сложности когда делали аля браузерную игру, где 2 человека отвечают на вопросы, проблема была в том что если у человека пропал интернет это я проверить стандартными методами не смог, пришлось делать метод куда с фронта раз в секунду приходил запрос что пользователь еще в сети.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@Sergey69ful Хм. То есть хук unsubscribed не срабатывал? Впрочем, это логично, если интернет неожиданно пропал
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@Sergey69ful В общем, не похоже, что это как-то починили github.com/rails/rails/issues/29307 Там есть предложение действительно слать пинги с сервера, но по факту всё это остаётся на откуп самому разработчику
@ddd2283
@ddd2283 Жыл бұрын
Может кто-то популярно объяснить такой момент: Все во всех мануалах дергают из StinulusJS бэк из разряда - await() - fetch() .... но почему так сложно то? Почему я как ленивый и тупой и тем более не переваривающий JS не могу из контроллера делать тупо - this.stimulate(ReflexController#Action)?
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Так это, я так понимаю, у вас ещё reflex используется?
@ddd2283
@ddd2283 Жыл бұрын
@@IlyaBodrovKrukowski Ну таки да, он прекрастно вписался в концепцию importmap, без необходимости webpackera как раньше. Он да еще CableReady очень дают широкий диапозон для фантазии.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@ddd2283 Я не пробовал его, честно говоря, но я так понимаю, что hotwire закрывает эту нишу
@ddd2283
@ddd2283 Жыл бұрын
​@@IlyaBodrovKrukowski Будем ждать, что кто-то приручит обоих зверей и осветит подробно :) Вообще у меня эссе на тему антикризисных технологий в период массовых миграций умов. Фулл стак на RoR в виртуальной машине Java(как некий стандарт который всем понятен). Спасибо что многое оч доходчиво доносите! Обязательно продолжайте!
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
@@ddd2283 Спасибо, стараюсь
@ledockol
@ledockol Жыл бұрын
Серьезный материал, точно будет полезен. Илья, огромное спасибо! Пять копеек, потенциально могут возникнуть проблемы, мне кажется, если лайки глубоко интегрированы в паршиал message и их оттуда тяжело вычленить. Да и сама реализация этого алгоритма довольно сложная. Ранее для решения подобных задач использовал несколько другой вариант: после лайка обновляю всем подписчикам счетчики лайков , а инициатору лайка броадкастом отдельно и только ему обновляю состояние кнопки лайка.У всех остальных состояние кнопок не меняется. Конкретную реализацию этого метода можно посмотреть у меня в гите: Real-Time-Comments-and-Voting-Hotwire. Там же есть и видео.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Спасибо, интересно Ну, да, это некие соображения по теме, можно и персонально отправлять по "выделенному" каналу, конечно - мне хотелось сделать именно так, чтобы канал один на всех и все уведомления приходят всем подписчикам
@codeline9387
@codeline9387 Жыл бұрын
вычисление автора сообщения можно решить без стимулуса, я делал примерно такое же приложение когда пробовал хотвайр и сделал примерно так, код из модели, но броудкастить из любого другого места не проблема: after_create_commit :send_message_to_chat_users def send_message_to_chat_users chat.chatable.users.each do |chat_user| broadcast_append_to locals: { message: self, owned: (user_id == chat_user.id) }, target: "messages-#{chat_id}-user-#{chat_user.id}" end end получается, что сообщение берем единожды, итерируюем пользователей комнаты и каждому отправляем сообщение, а паршал выглядит вот так:
@codeline9387
@codeline9387 Жыл бұрын
в моем случае не кнопка edit, а просто стилизация сообщения
@ledockol
@ledockol Жыл бұрын
@@codeline9387 Вариант хороший, но приемлем, ИМХО, когда известны конкретные получатели. Как быть когда на сайте присутствуют гости и тоже могут видеть сообщения? По ним мы не сможем итерироваться. Тогда вариант от Ильи со стимулом подойдет лучше. Или же переносить этот функционал в ActionCable... Прим. Кстати, кроме стимула рендер с учетом текущего пользователя возможен также на основе только css.
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
Спасибо, любопытно! Да, тут, как заметил Александр, тоже есть подводные камни - если честно, они в любом решении появляются в какой-то момент Но в целом реализация тоже достойна внимания
@IlyaBodrovKrukowski
@IlyaBodrovKrukowski Жыл бұрын
В этой реализации опять же, судя по всему, у нас вырисовывается потенциально очень много "персональных" каналов для рассылки. Это в целом не сильно страшно, но в целом rails - не то решение, которое может обслуживать много таких каналов (в отличие от erlang/elixir). Поэтому мне и хотелось в своём примере показать, что в теории канал может быть один, но тогда, конечно, приходится писать более сложный JS
@codeline9387
@codeline9387 Жыл бұрын
@@IlyaBodrovKrukowski каналов всегда будет много, каждый получатель обязан быть подписан на сокет, в любом случае рельса проитерирует получателей, но в данном случае действительно у нас может миллион пользователей, а онлайн только 2, тут уже можно дополнительно проверять в базе статус получателя если таковой есть
Путин. Прямая линия 2024. LIVE
AKIpress news
Рет қаралды 33 М.
REAL or FAKE? #beatbox #tiktok
01:03
BeatboxJCOP
Рет қаралды 18 МЛН
Арыстанның айқасы, Тәуіржанның шайқасы!
25:51
QosLike / ҚосЛайк / Косылайық
Рет қаралды 700 М.
Try this prank with your friends 😂 @karina-kola
00:18
Andrey Grechka
Рет қаралды 9 МЛН
Работа с LLM как с мозгом AI агента
1:27:21
Ilya Krukowski
Рет қаралды 564
Ruby on Rails 7, урок #25 | Turbo Frames, часть 2
14:51
Ilya Krukowski
Рет қаралды 1,4 М.
Агенты AI: Пишем простейшего агента
1:02:41
Про Kafka (основы)
49:23
Владимир Богдановский
Рет қаралды 419 М.
USA strikes Russia / Zelensky's statement on negotiations
15:12
NEXTA Live
Рет қаралды 542 М.