Turbo Hotwire — это здорово, мне очень нравится простота турбо-фреймов. Но после использования CableReady турбо-потоки кажутся немного ограниченными. Я был удивлен, когда не смог найти ни одного драгоценного камня/пакета, который бы улучшал турбо-потоки для создания пользовательских турбо-действий.
Отказ от ответственности: Этот пост не будет иметь большого смысла для вас, если вы не знакомы с турбо-потоками и StimulusJS.
Допустим, если вы хотите перенаправить на новую страницу после выполнения какой-то работы, или сбросить форму, нет способа сделать это с помощью турбо-потокового действия. С помощью CableReady вы можете сделать следующее
Поэтому мне стало интересно, как можно создать пользовательские действия турбопотока. Судя по тому, как DHH (оригинальный создатель Rails) обсуждал турбо-потоки, маловероятно, что turbo будет поддерживать больше действий, есть
ожидается PR, но мало что изменилось.
Так что же мы можем сделать сегодня?
Стимулирующие контроллеры на помощь
Мы можем имитировать паттерн, который используют турбо-потоки, с помощью StimulusJS. В StimulusJS есть метод жизненного цикла под названием connect, который выполняется, когда в DOM добавляется новый элемент со стимул-контроллером.
Для примера с перенаправлением мы можем написать что-то вроде этого:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
// take a value as an argument where to redirect
static values = { url: String }
connect() {
// perform wanted behavior
Turbo.visit(this.urlValue)
// clean up after action is executed
this.element.remove()
}
}
Таким образом, следующий html, добавленный в любое место тела, будет выполнять перенаправление:
<template data-controller="redirect" data-redirect-url-value="<%= your_redirect_url %>"></template>
Таким образом, с помощью турбо-потока мы можем прикрепить это к телу:
<%= turbo_stream.append_all "body" do %>
<template data-controller="redirect" data-redirect-url-value="<%= your_redirect_url %>"></template>
<% end %>
И браузер будет перенаправлен, учитывая этот ответ турбо-потока. BTW: Мы используем append_all
, чтобы мы могли добавлять в тело, не полагаясь на наличие элемента с определенным id.
Лучший опыт разработчика
Это не самое элегантное решение, но оно работает и имеет незначительные накладные расходы. Мы можем улучшить работу разработчиков, написав помощника, который позволит сделать что-то вроде:
<%= turbo_stream_action :redirect, url: "http://www.rstuder.ch" %>
Таким образом, мы можем написать помощник, создающий тег turbo stream, который будет добавляться к телу и преобразовывать хэш значений в значения для контроллера стимулов:
module TurboStreamHelper
def turbo_stream_action(action, **values)
controller_name = action.to_s.dasherize
data_attrs = {
"data-controller" => controller_name
}
data_attrs = values.each_with_object(data_attrs) do |(key, value), attrs|
attrs["data-#{controller_name}-#{key.to_s.dasherize}-value"] = value
end
turbo_stream.append_all "body" do
content_tag(:template, nil, data_attrs.merge)
end
end
end
Итак, мы получили простой API вокруг некоторых соглашений, который дает нам возможность создавать пользовательские действия и вызывать их с аргументами из шаблона turbo stream.
Заключение
Турбо-потоки с контроллерами стимулов дают нам достаточно возможностей для достижения пользовательских действий. Без дополнительных зависимостей. Если вы все равно используете CableReady, то взгляните на
этот пакет от замечательного Марко Рота, который позволяет вам использовать операции cable ready с турбо-потоками.
ps: Этот пост был первоначально опубликован на rstuder.ch