Prompting user confirmation in stimulus-reflex
Tags: rails, stimulus
Published: 2020-06-11 09:23:20

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

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/i0rpw11pjle3e3t2ntux.png)

---

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
```shell
$ rails g scaffold tasks title status
$ rake db:migrate
```

#### Step: 2 add stimulus_reflex and cable ready gems in `Gemfile` 

```ruby
gem 'cable_ready'
gem "stimulus_reflex", "~> 3.2"
```

```shell
 $ bundle install
```
#### Step: 3 update app/channels/application_cable/connection.rb

```ruby
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
```shell
$ rails g channel Tasks 
```

#### Step: 5 update `app/channels/tasks_channel.rb` 
```ruby
class TasksChannel < ApplicationCable::Channel
  def subscribed
    stream_from "tasks"
  end
end
```

#### Step: 6 update `app/javascript/channels/tasks_channel.js`
```javascript
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

```shell
rails g stimulus_reflex Tasks
```
#### Step: 8 Update `app/reflexes/tasks_reflex.rb`
```ruby
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`
```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`
```ruby
   class TasksController < ApplicationController
     include CableReady::Broadcaster
   end
```

`app/views/users/index.html.erb`
```html
<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.e `data-action` instead of `data-reflex` in links to show confirmation.