Forms & Pages
Build structured configuration and settings interfaces in your Avo admin using standalone forms and organized page hierarchies — no database models required.
Forms handle custom data processing, settings management, and workflows. Pages organize those forms into a sidebar-navigable interface with a main page and sub-pages.
Requirements
- Avo >= 4.0
- An active Avo license with the Forms add-on enabled
Installation
1. Add the gem
Add avo-forms to your Gemfile:
gem "avo-forms", source: "https://packager.dev/avo-hq/"Then install it:
bundle install2. Verify the engine loads
The engine registers itself automatically via Avo.plugin_manager. No initializer changes are required — start creating forms and pages right away.
Quick start
Create your first form
Generate a form with:
rails generate avo:form general_settingsThis creates app/avo/forms/general_settings.rb. Edit it to add fields and handle submission:
# app/avo/forms/general_settings.rb
class Avo::Forms::GeneralSettings < Avo::Forms::Core::Form
self.title = "General Settings"
self.description = "Configure your application"
def fields
field :app_name, as: :text, required: true
field :maintenance_mode, as: :boolean, default: false
end
def handle
# params contains submitted form data
flash[:notice] = "Settings saved"
default_response
end
endCreate a page to host your form
Generate a page:
rails generate avo:page settingsEdit app/avo/pages/settings.rb to wire in your form:
# app/avo/pages/settings.rb
class Avo::Pages::Settings < Avo::Forms::Core::Page
self.title = "Settings"
self.description = "Manage your application settings"
def navigation
page Avo::Pages::Settings::General, default: true
end
endCreate the sub-page app/avo/pages/settings/general.rb:
# app/avo/pages/settings/general.rb
class Avo::Pages::Settings::General < Avo::Forms::Core::Page
self.title = "General"
def content
form Avo::Forms::GeneralSettings
end
endAdd the page to your Avo menu
# config/initializers/avo.rb
Avo.configure do |config|
config.main_menu = -> {
section "Configuration", icon: "cog" do
page "Avo::Pages::Settings", icon: "adjustments"
end
}
endUsers can now navigate to Settings → General in the sidebar and submit the form.
How it works
Forms inherit from
Avo::Forms::Core::Form. They define fields viadef fieldsand handle submissions viadef handle. Thehandlemethod runs in the controller context, soparams,current_user,flash, andcookiesare all available directly.Pages inherit from
Avo::Forms::Core::Page. A main page (one namespace level deep, e.g.Avo::Pages::Settings) acts as a container and defines navigation. Sub-pages (deeper, e.g.Avo::Pages::Settings::General) define the actual content viadef content.Routes are resolved dynamically at request time — no manual route declarations needed. Pages live at
<root_path>/pages/<id>and forms at<root_path>/forms/<id>, whereiddefaults to the class path (e.g.Avo::Pages::Settings::General→settings/general) and can be overridden withself.id.Rendering: Pages render with a sidebar navigation listing all sub-pages. Each sub-page shows its title, description, and all registered forms in order.
Generators
Avo Forms ships generators for both building blocks. Use them to scaffold a class with the right structure, then fill in the fields, content, and navigation.
Form generator
rails generate avo:form your_form_nameCreates app/avo/forms/your_form_name.rb:
# app/avo/forms/your_form_name.rb
class Avo::Forms::YourFormName < Avo::Forms::Core::Form
self.title = "Your Form Name"
self.description = "Manage your your form name"
def fields
field :example, as: :text, default: "Hello World"
end
def handle
flash[:success] = { body: "Form submitted successfully", timeout: :forever }
flash[:notice] = params[:example]
default_response
end
endPage generator
rails generate avo:page your_page_nameCreates app/avo/pages/your_page_name.rb, with commented examples of every navigation and content declaration:
# app/avo/pages/your_page_name.rb
class Avo::Pages::YourPageName < Avo::Forms::Core::Page
self.title = "Your Page Name"
self.description = "A page for your page name"
# self.navigation_label = "Your Page Name"
def content
# form Avo::Forms::AnyFormClass
end
def navigation
# Reference an existing page class:
# page Avo::Pages::AnySubPageClass
# Show a form directly in the navigation:
# form Avo::Forms::AnyFormClass
# Declare a virtual page inline with its content:
# page "Custom Page",
# description: "A page for custom page",
# content: -> { form Avo::Forms::SomeForm }
end
endTo create a sub-page, generate the parent first and namespace the child under it — see how pages are organized.
Parsed once at boot
content and navigation are evaluated a single time during application boot. Keep them static — no conditional or dynamic logic inside them.