Updated Tutorial: How Do I Update My Model from a checkbox?

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.

2 thoughts on “Updated Tutorial: How Do I Update My Model from a checkbox?

Leave a Reply