The thing is here you don't want to be redirecting the user around. Instead they just stay on the index page and you just send the form submission with ajax and then append the new records to the existing document.
So lets start refactoring the form into a partial for resuse:
# deals/_form.html.haml
= simple_form_for(deal) do |f|
%div
= f.input :name
%div
= f.submit
And then lets put the form on the index view:
# deals/index.html.haml
%h1 Deals
= turbo_frame_tag "deal_form" do
= render "form", deal: @deal
= turbo_frame_tag "deals" do
= render @deals
We also need a turbo stream view for invalid form submissions:
# deals/new.turbo_stream.haml
= turbo_stream.replace "deal_form" do
= render partial: "deals/form", locals: { deal: @deal }
Here we are just using the progressive enhancement approach and both the form and deals are rendered on the initial page view. Using a turbo frame and not just div#deals
isn't actually doing that much in this case but it will later if you add the src
attribute for example to decompose the page.
Then lets setup the controller to stream either a new deal to to the list or "send the form back" with errors.
class DealsController < ApplicationController
# GET /deals or /deals.json
def index
@deals = Deal.all
end
# POST /deals or /deals.json
def create
@deal = Deal.new(deal_params)
respond_to do |format|
if @deal.save
format.html { redirect_to action: :index, notice: "Deal was successfully created." }
format.turbo_stream
else
format.html do
@deals = Deal.all
render :index, status: :unprocessable_entity
end
format.turbo_stream { render :new, status: :unprocessable_entity }
end
end
end
private
# Only allow a list of trusted parameters through.
def deal_params
params.require(:deal).permit(:name)
end
end
Turbo also provides methods to just render turbo streams straight for the the controller if what you're doing is simple enough that you don't need a view:
def create
@deal = Deal.new(deal_params)
respond_to do |format|
if @deal.save
format.html { redirect_to action: :index, notice: "Deal was successfully created." }
format.turbo_stream do
render turbo_stream: turbo_stream.prepend(:deals, partial: "deals/deal", locals: { deal: @deal })
end
else
format.html { render :new, status: :unprocessable_entity }
format.turbo_stream do
render turbo_stream: turbo_stream.replace(:deal_form, partial: "deals/form", locals: { deal: @deal })
end
end
end
end