Remote form with Rails
-
Note: The following is out of date. Updated recommendations here: https://h1rails.com/server_for_state
-
-
Views
-
Wrap your form in a div with a known id. You'll use this as your
hx-target
when the form is submitted. -
<div id="task-form"> <%= render partial: "partials/task_form" %> </div>
-
Write your form as normal, but use
hx-post
instead ofaction
, and specify ahx-target
-
# /views/partials/_task_form.html.erb <div class="flex flex-col space-y-3"> <% if @task.persisted? %> <div class="bg-blue-600 text-white p-5 rounded"> Great! Your details have been saved! </div> <% else %> <%= render partial: "shared/form_errors", locals: { record: @task } %> <form hx-post="<%= new_task_path %>" hx-target="#task-form" > <div class="grid grid-cols-7 md:space-x-4 space-y-3 md:space-y-0"> <div class="md:col-span-2 col-span-7"> <label for="name-field">Name</label> <input class="<%= 'invalid' if @task.errors[:name].present? %>" id="name-field" type="text" placeholder="Task Name" name="task[name]" value="<%= @task.name %>" /> </div> <div class="md:col-span-1 col-span-7"> <label> </label> <input type="submit" value="Submit"> </div> </div> </form> <% end %> </div>
-
Controller
-
Add a method to your application controller that looks out for the
HX-Request
header and responds without the full layout. -
class ApplicationController < ActionController::Base def support_partial_response if request.headers['HX-Request'] @async_request = true render :layout => false else render end end end
-
Now add that method to the final line of whatever controller action you'd like to support
-
class Tasks < ApplicationController def new if request.post? @task = Task.new(task_params) @task.save end support_partial_response end end
-