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.
You can setup the Todo model with this command:
$ rails g scaffold Todo title:string completed:boolean --no-assets --no-helper --no-test-framework
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, 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',
credentials: "include",
dataType: "script",
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 #add this at the beginning to make sure the form is populated.
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.