Skip to content

Blogging On Rails

Everything on Rails!

Stimulus.js Tutorial: How Do I Remotely Update My Model from a checkbox?

An updated version of this post can be found here: https://onrails.blog/2024/03/06/stimulusjs-tutorial-update-model-with-checkbox-using-turbo-morphing/

A previous update was here: https://onrails.blog/2020/11/09/updated-tutorial-how-do-i-update-my-model-from-a-checkbox/

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.

Feel free to leave comments or questions below.

Want To Learn More?

Try out some more of my Stimulus.js Tutorials.

Make Interactivity Default 

Make your web app interactive now with easy to implement and simple to add HOTWire integrations. 

Enter your email and get a free sample of my HOTWire Tutorials ebook.

We won’t send you spam. Unsubscribe at any time.

6 comments on “Stimulus.js Tutorial: How Do I Remotely Update My Model from a checkbox?”

Leave a Reply

Your email address will not be published. Required fields are marked *