Я посмотрел https://turbo.hotwired.dev/handbook/streams и https://www.hotrails.dev/turbo-rails/turbo-streams , но не понял, как это сделать. .
У меня длинная страница с множеством сообщений. Когда страница загружается, она должна передавать сообщения. Предположим, имеется 100 сообщений, и обработка каждого сообщения занимает 100 мс. Пользователь должен видеть одно сообщение каждые 100 мс, чтобы они отображались по мере потоковой передачи.
На индексной странице будет целевой идентификатор:
<div id = "messages"></div>
Кажется, будет частичное сообщение:
<turbo-stream action = "append" target = "messages">
<template>
<turbo-frame id = "message">
<%= message.text %>
</turbo-frame>
</template>
</turbo-stream>
Кажется, что контроллер может выглядеть так:
@messages = Message.last(100)
respond_to do |format|
format.html do
end
format.turbo_stream do
render turbo_stream: turbo_stream.append(:messages, partial: 'message',
locals: { collection: @messages })
end
end
Не уверен, будет ли транслироваться вся страница или только сообщения.
Если вся страница транслируется, то, как я понимаю, вам нужно заставить Rails визуализировать турбо_поток без запроса потоковой передачи. Но не знаю, как нацелиться на рамку _top.
Если передаются только сообщения, то, похоже, нам нужен механизм для запуска потоковой передачи при рендеринге индексной страницы. Не уверен, есть ли для этого команда JS Turbo...
Пожалуйста, не говорите мне, что это неправильно. Я знаю, что передавать много сообщений в потоковом режиме — плохая идея. Это упрощенный пример варианта использования. Этот упрощенный пример облегчает понимание без добавления дополнительного контекста.
Обновлено: Рельсы 7.1.2.





Обратите внимание, что турбопоток сам по себе не является потоковым ответом, это обычный http/html. Вы можете создать свой собственный Турбо-канал и транслировать с него:
# app/channels/messages_channel.rb
class MessagesChannel < Turbo::StreamsChannel
def subscribed
super
Message.last(100).each do |message|
MessagesChannel.broadcast_append_to(
verified_stream_name_from_params,
target: "messages",
partial: "messages/message",
locals: {message:}
)
end
end
end
# app/views/messages/_message.html.erb
<%= tag.div id: dom_id(message) do %>
<%= message.text %>
<% end %>
В вашем шаблоне:
<%= turbo_stream_from "messages", channel: "MessagesChannel" %>
<div id = "messages"></div>
turbo stream is not a streaming response - Я это понял после публикации. Я так понимаю, каждое сообщение будет транслироваться индивидуально, так что это тоже сработает.
В проекте приложения для социальных сетей для портфолио я реализовал подход для бесконечной прокрутки сообщений на временной шкале и страницах профиля с использованием Turboframes и Turbo Streams.
Во-первых, давайте лениво загрузим посты с контроллера в турбо-формате. Я также использую драгоценный камень will-paginate для нумерации страниц. Логика здесь заключается во втором теге турбо-фрейма, где мы снова лениво загружаем сообщения, если у нас остались какие-либо сообщения (на следующей странице). Отложенная загрузка происходит только тогда, когда этот компонент становится видимым на экране.
<%# app/views/timeline/index.html.erb %>
<%= turbo_frame_tag "posts", src: root_path(format: :turbo_stream), loading: :lazy %>
<% if @posts.next_page %>
<%= turbo_frame_tag "load_more", src: root_path(page: @posts.next_page, format: :turbo_stream), loading: :lazy %>
<% end %>
</div>
<div class = "mt-8">
<p class = "text-gray-500">🚀 Current page: <span id = "current_page"><%= @posts.current_page %></span></p>
</div>
Итак, когда мы получаем ответ турбопотока, мы добавляем сообщение к сообщениям и заменяем турбокадр load_more следующей страницей в качестве параметра, поэтому, когда пользователь прокручивает дальше вниз и этот load_more становится видимым, он загружает больше сообщений и процесс повторяется.
<%# app/views/timeline/index.turb_stream.erb %>
<%= turbo_stream.append "posts" do %>
<%= render partial: "posts/post", collection: @posts %>
<% end %>
<% if @posts.next_page %>
<%= turbo_stream.replace "load_more" do %>
<%= turbo_frame_tag "load_more", src: root_path(page: @posts.next_page, format: :turbo_stream), loading: :lazy %>
<% end %>
<% end %>
<%= turbo_stream.update "current_page", @posts.current_page %>
На стороне контроллера мы просто загружаем сообщения с нумерацией страниц и параметром страницы.
class HomeController < ApplicationController
def index
friend_ids = current_user.friends.pluck(:id)
friend_ids << current_user.id
# @posts = Post.paginate(page: params[:page], per_page: 1).order('created_at DESC')
@posts = Post.where(user_id: friend_ids).paginate(page: params[:page], per_page: 1).order('created_at DESC')
end
end
Таким образом, мы можем загружать огромные объемы данных на страницу с отложенной загрузкой и бесконечной прокруткой без какой-либо строки кода JavaScript.
Вы не делаете что-то неправильное, но вы думаете об этом неправильно. Вся идея декомпозиции состоит в том, чтобы создать впечатление, что страница загружается быстрее, поскольку пользователь может быстрее взаимодействовать со страницей, даже если на самом деле в целом требуется больше времени, прежде чем все будет загружено и отображено. Чего я не понимаю, так это почему вы думаете, что вам следует ориентироваться на фрейм
_top, поскольку это приведет к повторному рендерингу всей страницы.