- Stimulus: a lightweight JavaScript framework when it's not needed to do a roundtrip to the server
- Turbo Drive: automatically captures any link, merges the already loaded header to the response header and replaces the loaded body with the response body
- Turbo Frames: replaces only a specific part of the body
- Turbo Streams: handles multiple responses, like appending something or replacing something on the body
You need to wrap a section of your view with a turbo_frame_tag
. It can accept a model object, with
which Rails automatically infers its name. Or you can use dom_id
with the model object.
Just having a turbo-frame
element on the response is enough to have Turbo Frames replace only that
part of the application. However, it's possible to render only the changed part, and Turbo Frames will
take care of the rest.
Important: it's not possible to place a turbo frame inside of a HTML table element, as it's not a valid element inside a table. The workaround is to use a HTML div instead and style it as a table.
You may encounter a situation in which you place a link inside a frame, but the content should replace
the whole page. To "break out" of a frame, you need to add a data-turbo-frame element on this link,
as in link_to object, data: { turbo_frame: "_top" }
. This _top
value is a special value that means
the parent frame of that frame the link is in - or the whole document if there aren't any other frames.
It can also be used to state which frame, other than the link is in, the link's response should replace.
Turbo Streams are a response type within Rails. You create a turbo_stream.erb file and it will be rendered back as you have typed. If you want to replace a turbo frame and update a div content, you can write a file as in:
<%= turbo_stream.replace @bait, @bait %>
<%= turbo_stream.update "tackle_box_items_count", current_user.tackle_box_items.size %>
turbo_stream.replace
will first replace the @bait frame (which would be equivalent to
dom_id(@bait)
with the @bait
html.erb partial), then, update the content of the div with
id = tackle_box_items_count with the new count.
One caveat is a problem in that happens in other JavaScript technologies: updating a part of the HTML div via JavaScript will keep the content while you are on that page. However, if you hit the browser "back" button, any content updated via JavaScript will disappear, as it is cached in the Turbo Drive cache.
Add data-turbo-permanent
to the HTML element you want to keep the value to get around it.
Turbo Streams do not work only with Turbo Frames. It will work with any HTML element with a unique id.
These are the possible actions:
- replace: replaces the whole HTML element or Turbo Frame with the new content;
- update: replaces the inner content of the HTML element or Turbo Frame with the new content.
- append: adds the content to the end of the target element without changing its existing contents. For example, you want to add something to the bottom of a list.
- prepend: adds the content to the beginning of the target element without changing its existing contents. For example, you want to add something to the top of a list
- remove: removes the target element.
- before: adds the content before the target element. For example, you want to put a high-priority item before a lower-priority item.
- after: inserts the given content after the target element. For example, you want to put a February item after a January item.
To support HTML response, which is a desired thing when you practice unobtrusive JavaScript,
you can add a respond_to
block to your controller with a turbo_stream
format, such as:
respond_to do |format|
format.turbo_stream
format.html { redirect_to baits_url }
end
Adding a format.turbo_stream with no block will render the default action - in this case,
render the ACTION_NAME.turbo_stream.erb
Note: For simple responses, it's possible to render a turbo_stream action directly in the controller, as in:
render turbo_stream: turbo_stream.replace(@bait, @bait)
If you have a form that updates another section of the page when you submit it, such as a filter
form, the active field will lose focus every time you hit submit. You might think about using
turbo streams to empower this form and only update the results, but it's impossible to use turbo
streams in GET
requests.
This is a common situation, and there is a solution: using Turbo Frames. To do that, wrap your results in a Turbo Frame with a unique id, and then point your form to that frame:
form_with(url: search_path, data: { turbo_frame: "turbo_frame_unique_id", turbo_action: "advance" })
The turbo_action option will append the new URL to the browser history, making it possible to hit the "back" button and go to the previous results.
To create a Stimulus controller, you can either create the file manually then call the
rails stimulus:manifest:update
command, or create it via the Rails generator: rails g stimulus form
.
It will create an app/javascripts/controllers/form_controller.js
file and automatically run the
stimulus:manifest:update
task.