A Rails gem that extends ActionView::Helpers::FormBuilder with three automatic
behaviours designed to eliminate boilerplate in view templates.
Input, select, and textarea tags automatically receive HTML attributes derived from the model’s ActiveModel validators — no duplication between model and view:
| Validator | HTML attribute added |
|---|---|
validates :field, presence: true | required“required”= on inputs |
validates :field, presence: true | class“required”= on the matching label |
validates :field, length: { minimum } | minlength=N |
validates :field, length: { maximum } | maxlength=N |
Attributes that are already set explicitly in the view are never overwritten.
Pass required: nil to suppress the automatic required attribute.
A custom field_error_proc wraps each errored input in a .field_with_errors
div and appends one .error_message span per error message. Labels are left
unwrapped so they can be styled with the CSS :has() pseudo-class:
/* Style a label whose following sibling input has an error */
label:has(+ .field_with_errors) {
color: red;
}When the model passed to form_for / form_with has errors on :base, a
#error_explanation div is rendered before the <form> tag automatically:
<div id="error_explanation">
<ul>
<li class="error">Something went wrong.</li>
</ul>
</div>
<form ...>...</form>No manual error block is needed in the view.
The FormBuilder#submit override auto-sets data-disable-with via I18n, using
keys under helpers.disable_with.*:
# config/locales/en.yml
en:
helpers:
disable_with:
create: "Creating %{model}..."
update: "Saving %{model}..."Model-specific keys are also supported:
en:
helpers:
disable_with:
post:
create: "Publishing %{model}..."fields_for wraps nested model fields in a <fieldset> with the model’s DOM
class and a new CSS class appended when the record is unsaved.
f.group do … end wraps content in a <div class“group”>= — useful for
grouping related fields inside a form.
Add to your Gemfile:
gem 'smart_form_builder'Then run:
bundle installNo initializer is required. The Railtie wires everything up automatically via
ActiveSupport.on_load hooks.
Because SmartFormBuilder::FormBuilder is set as the default form builder for
all ActionController::Base subcontrollers, every form_for and form_with
call in your application automatically uses it.
<%# All three features are active with no extra code in the view %>
<%= form_for @post do |f| %>
<%= f.label :title %>
<%= f.text_field :title %> <%# required + maxlength inferred from validators %>
<%= f.label :body %>
<%= f.text_area :body %>
<%= f.submit %> <%# disable-with set automatically via I18n %>
<% end %>| Selector | When it appears |
|---|---|
#error_explanation li.error | errors[:base] is non-empty |
.field_with_errors | Any field-level validation error |
.field_with_errors span.error_message | Individual error message text |
label.required | Field has a PresenceValidator |
Inherit from SmartFormBuilder::FormBuilder instead of replacing it:
# app/helpers/application_helper.rb (or an initializer)
class MyFormBuilder < SmartFormBuilder::FormBuilder
# add project-specific helpers here
end
# config/application.rb or an initializer:
config.action_view.default_form_builder = MyFormBuilder- Ruby >= 3.1
- Rails >= 7.0 (
railties,actionview,activemodel)
MIT. See LICENSE.