This example demonstrates how you can achieve inline editing using Hotwire.
The description text is inside a turbo frame <turbo_frame id="product_description"><turbo_frame>
and a link to edit_product_description_path
.
# app/views/products/show.html.erb
<div>
<div class="flex justify-between text-xl font-medium text-gray-900">
<span><%= @product.name %></span>
<span><%= @product.price %></span>
</div>
<div class="mt-5">
<span class="text-gray-900 font-base">Description</span>
<span class="block mt-2 text-gray-500">
<%= turbo_frame_tag :product_description do %>
<%= link_to edit_product_description_path(@product) do %>
<%= @product.description || 'No description' %>
<% end %>
<% end %>
</span>
</div>
</div>
When a user clicks the link the request goes through the controller edit
action which renders app/product_descriptions/edit.html.erb
and returns it as HTML response.
# app/product_descriptions/edit.html.erb
<%= turbo_frame_tag :product_description do %>
<%= form_with(model: @product, url: product_description_path(@product), data: { turbo_frame: "_top"}) do |form |%>
<%= form.text_area :description, autofocus: true, class: "w-full border-gray-300 rounded-lg", rows: 5 %>
<div class="mt-2 space-x-3">
<%= form.submit "Save", class: "bg-gray-300 rounded-md px-2 py-1.5" %>
<%= link_to "Cancel", product_path(@product), class: "text-blue-600" %>
</div>
<% end %>
<% end %>
The response is wrapped with a frame with a matching id of the request container. This will replace the frame with new content which is a form with a text area to edit the description.
When the save button is clicked the form is submitted. This goes to the controller update
action that updates the product record and redirects back to the product show page.
# app/controllers/product_descriptions_controller.rb
class ProductDescriptionsController < ApplicationController
def edit; end
def update
@product.update!(product_params)
redirect_to product_path(@product)
end
private
def set_product
@product = Product.find(params[:product_id])
end
def product_params
params.require(:product).permit(:description)
end
end