Rails 7 Turbo/Hotwire Cheatsheet
My simple tutorial to remember how to wire up a basic SPA CRUD.
Last updated
My simple tutorial to remember how to wire up a basic SPA CRUD.
Last updated
The following is based on my takeaways from this tutorial:
Example: My app is simply a list with Tasks
. I want to create a single page app where I can:
Create new tasks
see the list of tasks
delete tasks from the list
in-line edit tasks on the list
Click "cancel" to cancel creation or editing of a task
mark tasks as complete or incomplete
Basic setup:
Create a scaffold for Tasks
, each has a title and completed
boolean
Change the root route to point to the Tasks index view. This will be our one page for our SPA.
That will be useful when giving turbo_frame_tags their IDs, which need to match a specific Task ID or "new_task". See below...
Near the top of the index view, we will have a button, "New task", and a place where we want to render the new task form when user clicks "New task".
There are 2 ways we can structure this:
Tasks controller index action should be structured like this:
be sure to define @task = Task new (this makes @task = "new_task" for the new task form).
Structure the index view like this.
Wrap the new task button in <%= turbo_frame_tag "task_form" do %>
The new task button simply points to new_task_path
Structure new.html.erb
like this:
This view must contain a <%= turbo_frame_tag id="task_form" do %>
...
When "New task" is clicked, its container (the turbo_frame_tag) will be replaced by the turbo_frame_tag found on the new.html.erb view (the form).
Structure index.html.erb like this:
The "New Task" button has a data attribute data: { turbo_frame: "task_form" }
which targets that turbo_frame_tag elsewhere on this page.
We place <%= turbo_frame_tag "task_form" %>
in the spot where we want to render the task form.
The new.html.erb is the same as above.
Now when user clicks "New task", it will render the new task form below where the button is. The button will remain visible.
Let's say we want to link the task title to the task show view.
Since the show view doesn't contain a turbo_frame_tag that matches the containing turbo_frame_tag of each task, we need to target "_top" for the link that points to the show view.
In _task.html.erb
I implemented the link that points the task title to the task show view like this:
We'll use turbo_streams for this.
This is the delete button inside each _task.html.erb
:
The destroy action in the tasks controller should look like this:
Create the file destroy.turbo_stream.erb
with this content:
Now when you click the "Delete" button, task is removed from the DOM and deleted.
The create action in tasks controller should be this:
Create file create.turbo_stream.erb
with this contents, which does this following:
Prepends the new task inside the dom element with ID "tasks"
Replaces the "new_task" form with the tasks form partial, and instantiates a new task by passing local variable: Task.new
Alternatively, we can use this block syntax to render the new task inside the "tasks" container:
Inside the _form.html.erb
partial, simply add the cancel link like this:
That points to the tasks index view (index.html.erb)
When user is in the new task form, then it will replace the "new_task" turbo_stream_tag with the contents of the "new_task" turbo_stream_tag found in index.html.erb
, which has no content. So it (correctly) replaces it with nothing.
When user is in the editing task form on any specific task, it will target that task's turbo_stream_tag (task_id
) and replace that with the contents of the the same turbo_stream_tag (task_id
) found on index.html.erb
which is the content of this task.