Turbo-frame basic : From a turbo-frame to the SAME turbo-frame

When the action PATCH /contracts/:id/kill is triggered from the index view we do not want to be redirect to the contract show, as usual, but instead stay in the index view and just UPDATE the contract card.

  1. Add a turbo-frame around the contract card

    #app/views/contracts/_contract.html.erb
    <%= turbo_frame_tag contract do%>
    [code for the contract card]
    <%end%>
    

    HTML generated ⬇️

    <turbo-frame id="contract_31" style="outline: rgb(186, 38, 139) dashed 2px;">
    
    [code for the contract card]
      
    </turbo-frame>
    

    As you can see when passing an AR object Turbo will generate a name based on the model and the object ID. (you can manually name the Frame ⇒ turbo_frame_tag “frame_name”)

    image.png

  2. And that’s it!! The turbo Magic will do the rest

From a Turbo-frame to another Turbo-Frame

When clicking on + to add a new contract, it triggers GET /contracts/new, we want the form to be insert, just above the contracts list.

image.png

  1. Add a turbo-frame tag in the the new view, turbo_frame_tag "new_contract"

    # app/views/contracts/new.html.erb
    
    [...]
      <h1 class="mb-4">Congrats You get a new Contrat</h1>
      <%= turbo_frame_tag "new_contract" do%>
        <%= render 'form',contract: Contract.new %>
      <% end %>
    [...]
    
    

    HTML generated ⬇️

    [...]
    <h1 class="mb-4">Congrats You get a new Contrat</h1>
    <turbo-frame id="new_contract">
    	[code from *form* partial]
    </turbo-frame>
    [...]
    

    image.png

  2. As we are not targeting the same TurboFrame, we need to specify the target name in the link using data attribute data-turbo-frame ="new_contract"

    # app/views/contracts/index.html.erb
    [...]
    <%= link_to new_contract_path, data:{turbo_frame: "new_contract"} do%>
      <i class="fa-solid fa-circle-plus text-black"></i>
    <% end %>
    [...]

Render a turbo stream

For create and destroy actions, the contract card is modified.

We will use the turbo-stream action to modify our list

  1. Add a new turbo-frame tag around the list

    image.png

    # app/views/contracts/index.html.erb
        <%= turbo_frame_tag "contracts" do%>
          <% @contracts.each do |contract| %>
            <%= turbo_frame_tag contract,  src:"/contracts/#{contract.id}", loading:"lazy" do%>
              LOADING
              <%#= render 'contracts/contract', contract: contract %>
            <% end %>
          <% end %>
        <% end %>
    
  2. Let’s modify the controller and create the turbo_stream view. Now the controller will have to render based on the request format :

      def create
        @contract = Contract.new(contract_params)
        @contract.save
        respond_to do |format|
          flash.now[:notice] = "A new target has been added"
          format.html { redirect_to contract_path(@contract) }
          format.turbo_stream
        end
      end
    
  3. Add the create.turbo_frame.erb

    # app/views/contracts/create.turbo_frame.erb
    <%= turbo_stream.prepend "contracts", @contract %> 
    <%#prepend the turbo-frame id="contracts with the render of the partial _contract
     with contract=@contract"%>
    <%= turbo_stream.replace "new_contract" do %>
      <%= turbo_frame_tag "new_contract" %>
    <%end%>
    <%# replace the turbo-frame id="new_contract" AKA the form frame, by an empty turbo-frame
    "new_contract"%>
    

List of turbo action

Turbo Reference