Skip to content

Instantly share code, notes, and snippets.

@joemasilotti
Created March 4, 2021 23:10
Show Gist options
  • Save joemasilotti/64418e47954ac4932f237d1a603d9db2 to your computer and use it in GitHub Desktop.
Save joemasilotti/64418e47954ac4932f237d1a603d9db2 to your computer and use it in GitHub Desktop.
Turbolinks + Turbo Native - Generic form handling with Stimulus

Turbolinks + Turbo Native - Generic form handling with Stimulus

These three files show how to handle forms with (legacy) Turbolinks in your Rails app with the new Turbo Native adapters.

  1. The Rails controller renders the form partial with an :unprocessable_entity status when encountering a form validation error
  2. The form is submitted via AJAX (local: false or remote: true depending on your Rails version)
  3. This is caught via the ajax:error->form#onError Stimulus action
  4. The Stimulus controller replaces the form's contents with the server-sided rendered HTML
  5. The native app is informed when the redirect occurs on a succesful submission

They are part of a series I'm writing on Hybrid iOS apps with Turbo. I'm currently writing the article on forms and basic authentication.

<% data = { controller: "form", action: "ajax:error->form#onError" } %>
<%= form_with(model: board_game, local: false, data: data) do |form| %>
<% if board_game.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(board_game.errors.count, "error") %> prohibited this board_game from being saved:</h2>
<ul>
<% board_game.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :name %>
<%= form.text_field :name %>
</div>
<div class="field">
<%= form.label :players %>
<%= form.number_field :players %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
class BoardGamesController < ApplicationController
def index
@board_games = BoardGame.all
end
def show
@board_game = BoardGame.find(params[:id])
end
def new
@board_game = BoardGame.new
end
def edit
@board_game = BoardGame.find(params[:id])
end
def create
board_game = BoardGame.new(board_game_params)
if board_game.save
redirect_to board_game, notice: 'Board game was successfully created.'
else
render_form(board_game)
end
end
def update
board_game = BoardGame.find(params[:id])
if board_game.update(board_game_params)
redirect_to board_game, notice: 'Board game was successfully updated.'
else
render_form(board_game)
end
end
def destroy
BoardGame.find(params[:id]).destroy
redirect_to board_games_url, notice: 'Board game was successfully destroyed.'
end
private
def board_game_params
params.require(:board_game).permit(:name, :players)
end
def render_form(board_game)
render partial: "form", locals: { board_game: board_game },
status: :unprocessable_entity
end
end
import { Controller } from "stimulus"
export default class extends Controller {
onError({ detail: [data, , xhr] }) {
this.element.innerHTML = xhr.response;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment