29
loading...
This website collects cookies to deliver better user experience
bundle add turbo-rails
and run bin/rails turbo:install
.turbolinks
to turbo
(eg. data-turbolinks-track
=> data-turbo-track
).this.isPreview
at app/javascript/controllers/notification_controller.js
) and replace it with data-turbo-cache="false"
at app/components/notification_component.html.erb
. Turbolinks.visit
with window.Turbo.visit
in app/javascript/controllers/notification_controller.js
.dom_id
helper to identify HTML parts related to each post.data: { turbo: false }
to each remote: true
link to disable Turbo on them. After that, it should work as before with Turbolinks.app/views/posts/destroy.js.erb
and replace it with Turbo stream..hidden
class to hide the post. That is something that Turbo can't do by default. Luckily, someone clever wrote an article about how to add a custom action to turbo streams. With that, we can refactor it.// app/views/posts/destroy.js.erb
// finding and hiding the record
document.getElementById('<%= dom_id(post) %>').classList.toggle('hidden');
// displaying the notification
<% flash.each do |type, data| %>
document.getElementById('notifications').insertAdjacentHTML("afterBegin", "<%=j render(NotificationComponent.new(type: type, data: data)) %>");
<% end %>
<!-- app/views/undo/destroy.turbo_stream.erb -->
<turbo-stream action="addclass" target="<%= dom_id(record) %>">
<template>hidden</template>
</turbo-stream>
<% flash.each do |type, data| %>
<%= turbo_stream.prepend('notifications', render(NotificationComponent.new(type: type, data: data))) %>
<% end %>
posts_controller.rb
and place it to app/controllers/concerns/destroy_with_undo_response.rb
, so we can easily reuse it. You can see that I also refactored it and added the Turbo stream support.# app/controllers/concerns/destroy_with_undo_response.rb
module DestroyWithUndoResponse
extend ActiveSupport::Concern
private
def destroy_with_undo_response(record:, job_id:, redirect:)
respond_to do |format|
format.html do
flash[:success] = undo_flash_message(klass: record.class, job_id: job_id)
redirect_to redirect
end
format.turbo_stream do
if params[:redirect]
flash[:success] = undo_flash_message(klass: record.class, job_id: job_id)
redirect_to redirect
else
flash.now[:success] = undo_flash_message(klass: record.class, job_id: job_id, inline: true)
render 'undo/destroy', locals: { record: record }
end
end
end
end
def undo_flash_message(klass:, job_id:, inline: nil)
timeout = defined?(klass::UNDO_TIMEOUT) ? klass::UNDO_TIMEOUT : 10
{
title: "#{klass.model_name.human} was removed",
body: 'You can recover it using the undo action below.',
timeout: timeout, countdown: true,
action: {
url: undo_path(job_id, inline: inline),
method: 'delete',
name: 'Undo'
}
}
end
end
PostsController
and update the destroy
action:class PostsController < ApplicationController
include DestroyWithUndoResponse
def destroy
post = Post.active.find(params[:id])
job_id = post.schedule_destroy
destroy_with_undo_response(record: post, job_id: job_id, redirect: posts_path)
end
end
app/views/posts/show.html.erb
and app/views/posts/_form.html.erb
we need to add a param redirect: true
to each post_path(@post)
. This param is then used in the turbo stream response to do the right action.app/views/posts/index.html.erb
we can remove remote: true, data: { turbo: false }
as we will leverage Turbo.