First, I’m going to assume you’ve read the Stimulus handbook, cover to cover, like I have.

Let’s say you have a Todo app, with a model Todo that has a string title, and a boolean field, completed. We are going to use Stimulus to update our model remotely on the server, when we check off the todo. And we’re going to use a nifty javascript API called fetch() to make it all happen.

So, in our Todos Controller, we’ll pull out all of our Todo records:

class TodosController < ApplicationController def index @todos = Todo.all end
end

And in index.html.erb, we’ll display the Todos, and put in the decorations that Stimulus will use:

<table> <% @todos.each do |todo| %> <tr data-controller="todo" data-todo-update-url="<%= todo_path(todo) %>"> <td> <input type="checkbox" data-action="todo#toggle" data-target="todo.completed" <% if todo.completed %> checked <% end %> > <%= todo.title %> </td> </tr> <% end %>
</table>

Now, let’s create our todo_controller.js and add the toggle method we specified above:

import { Controller } from "stimulus"
export default class extends Controller { static targets = [ "completed" ] toggle(event) { // Code to follow }
}

Inside the toggle(event) function, let’s start by getting the value of the checkbox, and put it into a FormData object:

let formData = new FormData()
formData.append("todo[completed]", this.completedTarget.checked);

Let’s post that data to the "update-url" value we set on the Todo row. We’ll set the method to PATCH so that it gets routed to our todo#update on our controller. The credentials and headers included ensure we send the session cookie and the CSRF protection token and prevent an ActionController::InvalidAuthenticityToken error.

fetch(this.data.get("update-url"), { body: formData, method: 'PATCH', dataType: 'script', credentials: "include", headers: { "X-CSRF-Token": getMetaValue("csrf-token") },
})

We can take the Response object and verify that our request was successful. If there was an error, we’ll revert the checkbox change.

.then(function(response) { if (response.status != 204) { event.target.checked = !event.target.checked }
})

Now, let’s go back to our ruby controller, and add our update method:

def update @todo = Todo.find_by_id params[:id] @todo.update todo_params @todo.save respond_to do |format| format.js end
end private def todo_params params.require(:todo).permit(:title, :completed)
end

Now when we check or uncheck one of the check boxes, an AJAX request is sent to our Rails app, and stimulus handles the response.

Comments or Questions? Find me on twitter @jpbeatty

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.