Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
July 7, 2021 07:57 pm GMT

Modern Rails flash messages (part 3): Refactoring with Turbo

I can not believe it has been almost 10 months since I wrote the first part. Several things have happened since then. Like Turbo...

The demo application still works in the same way, but a few changes needed to be made to support Turbo. I also refactored it a little bit to make it easier to use with multiple controllers.

I've updated the code at the repository on GitHub with the support for Turbo.

Installing Turbo

That was really easy, just run bundle add turbo-rails and run bin/rails turbo:install.

Don't forget to replace any mention of turbolinks to turbo (eg. data-turbolinks-track => data-turbo-track).

Usage with UJS and Turbo

The original solution worked with UJS and Turbolinks. Let's make it work in the same way but with Turbo. You can see mentioned changes here.

Thanks to Turbo, we can remove code related to Turbolinks cache (this.isPreview at app/javascript/controllers/notification_controller.js) and replace it with data-turbo-cache="false" at app/components/notification_component.html.erb.

We also need to replace Turbolinks.visit with window.Turbo.visit in app/javascript/controllers/notification_controller.js.

I also started using the dom_id helper to identify HTML parts related to each post.

The last thing I need to mention is adding data: { turbo: false } to each remote: true link to disable Turbo on them. After that, it should work as before with Turbolinks.

BTW you should check out mrujs as a modern replacement for UJS. Konnor Rogers did an amazing job there.

Refactoring and usage with Turbo streams

You can see mentioned changes here.

The main goal here is to refactor the JS response for the undo action at app/views/posts/destroy.js.erb and replace it with Turbo stream.

The first thing that it does is adding a .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.

From this:

// app/views/posts/destroy.js.erb// finding and hiding the recorddocument.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 %>

To the same functionality with Turbo stream:

<!-- 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 %>

Now, we could use that. Let's move the response from 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.rbmodule 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'      }    }  endend

We can now include it in the 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)  endend

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

In app/views/posts/index.html.erb we can remove remote: true, data: { turbo: false } as we will leverage Turbo.

And that's all. The application now behaves exactly the same, but with Turbo.


Original Link: https://dev.to/citronak/modern-rails-flash-messages-part-3-refactoring-with-turbo-25e6

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To