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
controller
i.edata-action
instead ofdata-reflex
in links to show confirmation.
Top comments (1)
Thanks for the post! I arrived at a slightly different solution.