rolmodel:slimrolemodel:webpackrolemodel:optics:baserolemodel:optics:icons- not to run, but by runtime expects aniconhelper to exist
- Custom confirm dialogs via
@rolemodel/turbo-confirmintegration - RoleModel Modal pattern integration. See Notes below for usage documentation.
- RoleModel Panel pattern integration, if run with the
--panelsflag. - some generally useful, global Turbo before-morph handlers.
Important
This generator does not provide RoleModel Panel integration, unless run with the --panels flag.
There are a couple of important rules when it comes to TurboFrames & forms.
- In the case of errors, your controller action must respond with
status: :unprocessable_contentHTTP status code 422 in order to re-render your form w/ errors. This is both a Turbo requirement, as well as the mechanism which prevents the modal or panel from re-animating in. - In the case of success, your controller action should redirect. This request should automatically inherit the turbo-frame layout, which is missing the targeted
modalorpanelturbo-frame and will therefore trigger the includedturbo:frame-missingevent handler. - Never use the
layoutclass method in your controllers. The RoleModel Modal pattern relies on Turbo-Rails' layout mechanics, which are overridden by the layout class method (even in an ancestor controller). If your design requires multiple layouts, you have 2 options:- ⭐ PREFERRED ⭐ Create a new subclass of ApplicationController and name it after your alternate layout. Subclasses of layout only controllers gracefully inherit their namesake layout without breaking Turbo. 🎉
- You may call the
layoutclass method with the symbolized name of a method which conditionally returns false e.g.'my_special_layout' unless turbo_frame_request?
e.g.
class FullscreenController < ApplicationController
# - LAYOUT ONLY -
# Subclasses inherit the "Fullscreen" layout as their default.
end
class SomethingsController < FullscreenController
def new
@something = authorize Something.new
render layout: 'modal'
end
def create
@something = authorize Something.new(some_params)
if @something.save
redirect_to @something, notice: 'Something created successfully'
else
render :new, status: :unprocessable_entity, layout: 'modal'
end
end
def show
@something = authorize Something.find(params[:id])
# gracefully rendered within the "fullscreen" layout!
end
endFor a detailed explanation of the RoleModal Modal pattern, see this blog post: TurboFrame Modals – The Definitive Guide
The included modal layout includes slots for title content & submit buttons, in addition to the main content yield. You may, of course remove these sections if they don't match your use-case. Otherwise, the following is an example edit template meant to be rendered in the modal layout.
= content_for :modal_header do
h2 Edit the thing
= content_for :modal_footer do
= button_tag 'Save', class: 'btn btn--primary', form: dom_id(@thing, :edit)
= simple_form_for @thing do |f|
= f.input :name
= f.input :descriptionnote: the submit button in the new.html.slim version of this template would be form: dom_id(@thing) or simply form: 'new_thing'.
Alternatively, it's still possible to nest the content_for block within the form builder if you need to leverege button text generation, for example. Though you must still set the form attribute explicitly, because the button (or input[type='submit'] in this case) will ultimately be rendered outside of the <form></form> tags. e.g.
= simple_form_for @thing do |f|
= f.input :name
= f.input :description
= content_for :modal_footer do
= f.submit form: f.idFor further explanation of form Id generation, see the Record Identifier and polymorphic Routes docs, or simply inspect the form element in your browser.
Modal: (the following 2 examples are equivalent)
= link_to 'Modal Test', some_modal_layout_action_path, data: { turbo_frame: 'modal' }= modal_link_to 'Modal Test', some_modal_layout_action_path
Panel: (the following 2 examples are equivalent)
= link_to 'Panel Test', some_panel_layout_action_path, data: { turbo_frame: 'panel' }= panel_link_to 'Panel Test', some_panel_layout_action_path
You'll then need to pass the layout kwarg when calling render with either modal or panel, depending on which frame is being targeted.
= button_to "Test Confirm", model, method: :delete, data: { \
turbo_confirm: "For real?!?",
confirm_details: "You're about to delete #{model.name}, forever. 😱",
confirm_button: "YOLO!",
}data attributes other than turbo-confirm are optional & customizable. See turbo-confirm for more details.