Introduction
StimulusReflex along with cable_ready is a wonderful option for creating reactive application.
One issue I face is how to prompt a user before deleting a record. This post is about how to deal this one.
Assume we have tasks list as follows and we need to prompt the user to confirm when he/she tries to remove a record.
| Title | Status | Remove | 
|---|---|---|
| Fix homepage css issue | Mark as resolved | Remove | 
| Add new banner | Mark as resolved | Remove | 
| Iphone support | Resolved | Remove | 
Step: 1: create scaffold and migrate
$ rails g scaffold tasks title status
$ rake db:migrate
  
  
  Step: 2 add stimulus_reflex and cable ready gems in Gemfile
gem 'cable_ready'
gem "stimulus_reflex", "~> 3.2"
 $ bundle install
Step: 3 update app/channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user
    def connect
      self.current_user = find_verified_user
    end
    private
      def find_verified_user
        if verified_user = User.find_by(id: cookies.encrypted[:user_id])
          verified_user
        else
          reject_unauthorized_connection
        end
      end
  end
end
Step: 4 create tasks channel
$ rails g channel Tasks 
  
  
  Step: 5 update app/channels/tasks_channel.rb
class TasksChannel < ApplicationCable::Channel
  def subscribed
    stream_from "tasks"
  end
end
  
  
  Step: 6 update app/javascript/channels/tasks_channel.js
import cableReady from 'cable_ready'
import consumer from "./consumer"
consumer.subscriptions.create("TasksChannel", {
  received(data) {
    if (data.cableReady) cableReady.perform(data.operations)
  }
});
Step: 7 generate tasks reflex
rails g stimulus_reflex Tasks
  
  
  Step: 8 Update app/reflexes/tasks_reflex.rb
class TasksReflex < ApplicationReflex
  include CableReady::Broadcaster
  def update
    id = element.dataset[:id]
    task = Task.find(id)
    task.update(status: "resolved")
    cable_ready["tasks"].text_content(
      selector: "status-col-#{id}",
      text: 'Resolved'
    )
    cable_ready.broadcast
  end
  def remove(id)
    task = Task.find(id)
    task.destroy 
    # in views we have set id for each row
    # cable_ready["tasks"]- here `tasks` denote channel name
    cable_ready["tasks"].remove(
      selector: "row-#{id}"
    )
    cable_ready.broadcast
  end
end
  
  
  Step: 9 Update app/javascript/controllers/tasks_controller.js
import ApplicationController from './application_controller'
export default class extends ApplicationController {
  remove(event) {
    event.preventDefault();
    // This is where we are prompting the user for confirmation
    const ok = confirm("Are you sure to mark the task as 'resolved'?")
    if(!ok){
      return false;
    }else{
      const el = event.currentTarget
      const id = el.getAttribute("data-id");
      this.stimulate("TasksReflex#delete", id)
    }
  }
}
  
  
  Step: 9 Update app/controllers/tasks_controller.rb
   class TasksController < ApplicationController
     include CableReady::Broadcaster
   end
app/views/users/index.html.erb
<table>
  <thead>
   <tr> 
      <th>Title</th>
      <th>Status</th> 
      <th>Remove</th> 
   </tr>
  </thead> 
  <tbody>
    <% @tasks.each do |task| %>
      <!-- unique row id  -->
      <tr id="row-<%= task.id %>">
        <td><%= task.title %></td>
        <td id="status-col-<%= task.id %>">
          <!-- directly call StimulusReflex -->
          <%= link_to 'Mark as resolved', '#',  data:{reflex: 'click->TasksReflex#update', id: task.id} %>
        </td>
        <td data-controller="tasks">
          <!-- Call controller instead of Reflex to show confirmation --> 
          <%= link_to 'Remove', '#', data:{action: "click->tasks#remove", id: task.id} %> 
        </td>
      </tr>
    <% end %>
  </tbody> 
</table>
Note: We need to use
controlleri.edata-actioninstead ofdata-reflexin links to show confirmation.

    
Top comments (1)
Thanks for the post! I arrived at a slightly different solution.