Fieldsets
Fieldsets são blocos de agrupamento usados para organizar visualmente e logicamente os campos, componentes e até outros fieldsets dentro de uma tela no Nerdify. Eles representam estruturas aninhadas e altamente configuráveis que controlam como a interface será montada no frontend.
📦 No frontend, um
fieldsetse comporta como um container dentro de um formulário, mas com recursos adicionais como cabeçalho, colapsamento e suporte a abas.
🧩 O que pode conter um fieldset
Um fieldset pode conter:
fieldsetsfilhos (aninhados)fields(campos do modelo)components(gráficos, botões, tabelas, cards, etc.)embeds(relacionamentos aninhados)
Essa flexibilidade permite compor estruturas visuais complexas com organização modular.
🧠 A definição de como utilizar
fields,embedsecomponentsserá explicada nas seções respectivas da documentação sobre cada um.
🔧 Parâmetros de configuração de um fieldset
| Parâmetro | Tipo | Descrição |
|---|---|---|
name | Symbol | Nome do fieldset (obrigatório) |
header | Boolean | Exibe um título no topo com o nome traduzido do fieldset |
minify | Boolean | Permite minimizar/expandir o conteúdo via caret |
tab | Symbol | Se definido, o fieldset é transformado em uma aba |
size | Integer | Número de colunas no grid (1 a 12) |
styles | Hash | Estilizações customizadas como background, padding, border, etc. |
backend_if | String | Condição avaliada no backend. Ex: can?(:edit, object) |
render_if | String | Condição avaliada no frontend. Se falsa, o bloco não é renderizado |
show_if | String | Condição avaliada no frontend. Se falsa, o bloco é renderizado mas oculto |
🔎 Entendendo as condições:
backend_if:→ executado no backend commodel,object,current_user,current_ability, etc.render_if:→ condição avaliada no frontend. Se falsa, o botão nem é renderizado.show_if:→ também é avaliada no frontend, mas apenas esconde o botão comhidden, mantendo o DOM.🔗 Enquanto
backend_ifutiliza uma string que representa código ruby e tem acesso a recursos que existem no controlador, comoobject,model,params, entre outros, orender_ifeshow_ifgeram código na sintaxe javascript para o frontend usando dados que estão presentes na resposta json que monta a página com placeholeders, por exemplo,resource.id == page.resources.current_user.id
Você também pode passar qualquer outra chave customizada, que será incluída na estrutura final e poderá ser usada nos templates para lógica personalizada. Exemplo:
fieldset :documents, header: true, info: :test, custom_flag: true do
field :cpf
field :rg
end
Esses valores (info, custom_flag) podem ser utilizados nos templates customizados para lógica condicional ou estilização dinâmica.
🔀 Fieldsets personalizados por controlador
Você pode criar fieldsets que só aparecem em determinados controladores utilizando backend_if como critério condicional. Isso permite definir todas as possibilidades de uso do modelo em um só lugar (o arquivo do modelo), mantendo controle centralizado da regra de negócio e suas representações visuais.
Sem backend_if, o fieldset estará disponível em todos os controladores que utilizarem o modelo. Com backend_if, você pode limitar a exibição a determinados cenários, como no exemplo:
fieldset :demo, backend_if: "params[:controller] == 'admin/clientes'" do
field :demo_field
end
🎯 Isso evita a duplicação de lógica em várias telas/controladores e garante que qualquer modificação em campos ou agrupamentos possa ser feita no próprio modelo, com impacto direto e controlado nos lugares certos.
Essa abordagem também permite garantir que tudo sobre como utilizar o modelo esteja concentrado em um só lugar. Ou seja, mesmo que o modelo seja usado por diferentes controladores e fluxos, todas as variações de campos, agrupamentos e lógica visual podem ser declaradas no próprio modelo — com controle por backend_if quando necessário.
🔐 Segurança dos campos e proteção de parâmetros
Por padrão, os controladores do Nerdify utilizam os fieldsets para determinar quais atributos são aceitos em requisições. Isso significa que somente os campos definidos dentro de fieldsets serão permitidos para criação ou atualização de registros.
Existem duas formas de proteger campos:
- Fora de qualquer fieldset
fieldset :demo do
end
field :secret_field, type: String
Esses campos não serão visíveis em nenhuma interface nem aceitos em parâmetros de requisição — usados apenas internamente, como em callbacks ou métodos. Se você utilizar esta opção de definir o field fora do fieldset, você precisa usar a sintaxe de definição de campos do ORM utilizado, no caso, MongoID.
- Dentro do fieldset com
protected: true
fieldset :demo do
field :secret_field, type: :string, protected: true
end
Nesse formato, você pode utilizar a sintaxe padrão da DSL do Nerdify.
Definindo o campo dentro do fieldset e usando protected, os campos serão visíveis, mas não poderão ser atualizados via requisição ou formulário do frontend. Eles serão ignorados mesmo que sejam passados como parametro na requisição e estejam presentes no formulário.
🔐 Essa proteção é baseada nos
strong_parametersdo Rails e evita ataques como mass assignment.
Você também pode proteger campos apenas em controladores específicos:
field :secret_field, type: :string, protected: { only: %w[admin/clientes] }
field :other_secret_field, type: :string, protected: { except: %w[admin/clientes] }
Além disso, é possível combinar backend_if com protected.
field :secret_field, type: :string, protected: { only: %w[public/customers] }, backend_if: "%w[admin/customers public/customers].include? params[:controller]"
No exemplo acima, o campo vai ser visível nos dois controladores, admin/customers e public/customers mas apenas no controlador admin/customers ele poderá ser alimentado ou atualizado.
🔐 Você deve ter cuidado ao utilizar
backend_ifpara esconder campos que deveriam ser protegidos. Obackend_ifpor si só apenas esconde, mas se o campo estiver dentro do fieldset, ele só será protegido a partir da definição dos valores do atributoprotected.
🧪 Exemplo completo de fieldset com filhos
fieldset :customer, header: true, minify: true, size: 12 do
field :name, type: :string
field :email, type: :email
fieldset :addresses_info, tab: :address_title do
embed :addresses, include: true
end
fieldset :documents, tab: :documents do
component :text, :document_name, type: :span
end
end
🧭 Nesse exemplo, o fieldset
customerterá um cabeçalho, será minimizável e conterá dois fieldsets filhos renderizados como abas (endereços e documentos). O nome da aba será traduzido automaticamente com base emtab: :address_title.
🧭 Form Wizard com Fieldsets
O Nerdify permite criar formulários em etapas (Form Wizard) utilizando apenas a configuração declarativa dentro dos próprios fieldsets.
Essa funcionalidade é ideal para dividir grandes formulários em múltiplas etapas visuais, com controle total sobre quais blocos aparecem em cada momento, de forma reativa e integrada com actions e callbacks do modelo.
🚦 Como configurar um Form Wizard
Você deve definir um fieldset pai com os parâmetros adicionais no fieldset, específicos para esta funcionalidade:
| Parâmetro | Tipo | Descrição |
|---|---|---|
steps | Array | Lista com os nomes das etapas (ex: %w[início dados resumo]) |
step_icons | Array | (opcional) Ícones correspondentes a cada etapa (ex: %w[home info check]) |
fieldset :sale_form, steps: %w[step_name1 step_name2], step_icons: %w[icon_name1 icon_name2] do
# fieldsets filhos aqui
end
Cada fieldset filho deve incluir a opção form_wizard:, indicando por um número a qual etapa ele pertence.
fieldset :step1_name, form_wizard: 1 do
field :type
field :tipo
end
fieldset :step2_name, form_wizard: 2 do
field :value
field :quantity
end
🎨 Os fieldsets com
form_wizardserão automaticamente organizados em um wizard visual com barra de progresso no frontend padrão do Nerdify.
⚙️ Avançando entre etapas com Actions
A transição entre etapas do form wizard é feita via actions.
Você deve configurar o params da action para informar a próxima etapa desejada, usando o parâmetro form_wizard.
action :next, on: :member, only: %w[edit], click: {
post: "/sales/:resource.id",
data: { venda: ":resource" },
params: { form_wizard: 2 },
success: { toast: :success, update: "resource" }
}
🔁 Esse comportamento pode ser usado em múltiplos botões como "Avançar", "Voltar", "Finalizar" etc.
🔒 Validando etapas com Callbacks
Você pode utilizar o valor do form_wizard atual (enviado no params) dentro dos seus callbacks de validação para criar regras condicionais por etapa.
Por exemplo:
before_validation :validate_step3, if: -> { form_wizard.to_i == 3 }
def validate_step3
if value < 0
errors.add(:value, :invalid)
end
end
🔍 O parâmetro
form_wizardestará disponível dentro do ciclo de vida da requisição como um método no modelo (form_wizard) e pode ser usado para pular validações desnecessárias em etapas anteriores.
✅ Benefícios do Form Wizard no Nerdify
- Divisão lógica e visual das etapas de um formulário complexo
- Navegação fluida controlada por
actions - Validações dinâmicas com
form_wizard.to_i - Controle total via backend — sem precisar escrever lógica no frontend
- Total integração com DSL do Nerdify (fieldsets + actions + callbacks)
💡 Dica
Combine o uso de form_wizard, protected: true, backend_if e render_if para montar formulários altamente dinâmicos, seguros e declarativos, com validações específicas para cada fase.
🧠 Todas as etapas, botões e lógica permanecem centralizadas no modelo e nos controladores, seguindo o padrão do Nerdify de backend descritivo e frontend automático.
Esse bloco pode ser inserido logo após a seção de tabs nos fieldsets para manter a coerência do conteúdo. Se quiser, posso atualizar diretamente sua versão do documento também!
🎨 Estilo visual com styles
O Nerdify aplica por padrão o estilo definido na constante Nerdify::Component::FIELDSET em cada fieldset. Você pode sobrescrever algum dos valores mantendo o restante usando o merge na constante:
fieldset :name, styles: Nerdify::Component::FIELDSET.merge({background_color: :primary}) do
end
Ou substituir completamente definindo o hash diretamente:
fieldset :name, styles: { background_color: :primary } do
end
A estilização padrão de um fieldset é a seguinte:
{
background: 'white',
border: {left: 1, top: 1, right: 1, bottom: 1},
padding: {left: 3, top: 3, bottom: 3, right: 3},
rounded: {top_left: 2, top_right: 2, bottom_left: 2, bottom_right: 2},
wizard_color: 'primary',
wizard_contrast_color: 'white',
color: 'dark',
border_color: 'default',
shadow: 0,
blur: 0,
margin: {
left: 0,
right: 0,
top: 0,
bottom: 2
},
align: {
top: 'left',
left: 'left',
right: 'right',
bottom: 'left',
body: 'left'
},
vertical_align: { default: 'stretch',
top: 'center',
left: 'center',
right: 'center',
bottom: 'center',
body: 'center'
},
orientation: {
top: 'horizontal',
bottom: 'horizontal',
left: 'horizontal',
right: 'horizontal',
body: 'horizontal'
},
font_size: '',
font_weight: ''
}
🔍 Acessando os fieldsets em tempo de execução
Você pode acessar a estrutura definida com:
Customer.nerdify.fieldsets
Isso retorna um array de objetos OpenStruct com todas as opções e filhos definidos. Exemplo:
fieldset = Customer.nerdify.fieldsets.first
puts fieldset.name # => :dados_gerais
puts fieldset.options[:header] # => true
puts fieldset.fieldsets.size # => 2
Os fieldsets são essenciais para estruturar e organizar as telas no Nerdify, mantendo modularidade, clareza visual e controle condicional — tudo de forma declarativa e automatizada. 🚀