As JSON
O método as_json no Nerdify controla como os modelos são serializados para JSON. O framework fornece um método default_json que processa automaticamente todos os campos definidos nos fieldsets.
⚙️ Funcionamento Padrão
O Nerdify gera automaticamente o JSON baseado nos campos definidos:
class Customer
include Nerdify::Model
orm :mongoid
fieldset :customer_form do
field :name, type: :text
field :email, type: :email
field :total_purchases, type: :money
field :status, type: :select, inclusion: %w[active inactive]
end
end
# Serialização automática:
customer.as_json
# => {
# id: "507f1f77bcf86cd799439011",
# _id: "507f1f77bcf86cd799439011",
# name: "João Silva",
# email: "joao@email.com",
# total_purchases: 1500.50,
# status: "active"
# }
📝 Comportamento por Tipo de Campo
O default_json aplica formatação específica por tipo:
| Tipo do Campo | Formato no JSON |
|---|---|
:money | Convertido para Float via .to_f |
:date | Formato ISO 8601 |
:date_time | Formato ISO 8601 com timezone |
*_id (relacionamento) | ID como String + campo *_id_label |
*_ids (relacionamento múltiplo) | Array de IDs como Strings |
:dropzone, :file | Array com URLs |
| Outros | Valor direto |
🎨 Customizando o JSON
Padrão: Merge com default_json
A forma recomendada é usar merge para adicionar campos:
def as_json(options = {})
default_json(options).merge({
full_address: "#{street}, #{number} - #{city}",
formatted_phone: phone.gsub(/(\d{2})(\d{5})(\d{4})/, '(\1) \2-\3'),
total_formatted: total.to_money.format
})
end
Customização Condicional
Use o parâmetro options para customizar por contexto:
def as_json(options = {})
json = default_json(options)
case options[:template]
when "show"
json.merge({
detailed_info: calculate_detailed_info,
related_records: related_records.map(&:as_json)
})
when "index"
json.merge({
summary: brief_summary
})
else
json
end
end
Removendo Campos
Para remover campos do JSON padrão:
def as_json(options = {})
default_json(options).except(:sensitive_data, :internal_notes)
end
🔗 Relacionamentos
Campos de Relacionamento Simples
Para campos belongs_to, o Nerdify automaticamente inclui:
field :customer_id, type: :select, collection: "/customers"
# JSON gerado:
{
customer_id: "507f1f77bcf86cd799439011",
customer_id_label: "João Silva" # Nome do cliente (automático)
}
Relacionamentos Múltiplos
Para has_and_belongs_to_many:
field :tag_ids, type: :select, collection: "/tags", multiple: true
# JSON gerado:
{
tag_ids: ["id1", "id2", "id3"],
tag_ids_label: ["Tag 1", "Tag 2", "Tag 3"]
}
Incluindo Objetos Relacionados
Para incluir objetos completos:
def as_json(options = {})
default_json(options).merge({
customer: customer&.as_json,
items: items.map { |item| item.as_json }
})
end
💰 Formatação de Valores Monetários
O Nerdify usa a gem money-rails. Para formatar valores:
def as_json(options = {})
default_json(options).merge({
# Valor numérico (para cálculos)
price_value: price.to_f,
# Valor formatado (para exibição)
price_formatted: price.to_money.format, # "R$ 1.500,00"
# Valor em centavos
price_cents: price.to_money.cents # 150000
})
end
📅 Formatação de Datas
def as_json(options = {})
default_json(options).merge({
# Data formatada para exibição
birth_date_formatted: birth_date&.strftime("%d/%m/%Y"),
# Data e hora formatada
created_at_formatted: created_at&.strftime("%d/%m/%Y %H:%M"),
# Descrição relativa
created_ago: time_ago_in_words(created_at)
})
end
🧮 Campos Calculados
Adicione campos que não existem no modelo:
def as_json(options = {})
default_json(options).merge({
# Cálculos
profit_margin: ((price - cost) / price * 100).round(2),
# Agregações
total_sales: sales.sum(:total),
sales_count: sales.count,
# Status derivados
is_vip: total_purchases > 10000,
days_since_last_purchase: (Date.today - last_purchase_date).to_i
})
end
🔒 Campos Sensíveis
Nunca exponha dados sensíveis no JSON:
def as_json(options = {})
# Remove campos sensíveis
default_json(options).except(
:password_digest,
:api_secret,
:credit_card_number
)
end
Para campos que só admins podem ver:
def as_json(options = {})
json = default_json(options)
unless current_ability&.can?(:manage, self)
json = json.except(:cost, :profit_margin, :supplier_price)
end
json
end
📊 Objetos Embarcados
Para documentos embarcados (Mongoid embeds_many):
def as_json(options = {})
default_json(options).merge({
addresses: addresses.map do |addr|
{
street: addr.street,
number: addr.number,
city: addr.city,
is_default: addr.default?
}
end
})
end
🎯 Opções Comuns
| Opção | Uso |
|---|---|
options[:template] | Contexto da view (show, index, edit) |
options[:include] | Relacionamentos a incluir |
options[:except] | Campos a excluir |
options[:only] | Apenas estes campos |
💡 Boas Práticas
✅ Faça
- Sempre chame
default_json(options)primeiro - Use
mergepara adicionar campos - Formate valores monetários e datas
- Remova campos sensíveis
❌ Evite
- Substituir completamente o
default_json - Expor dados sensíveis
- Queries N+1 (use
includesno controller) - Lógica complexa no
as_json
📋 Exemplo Completo
class Sale
include Nerdify::Model
orm :mongoid
def as_json(options = {})
json = default_json(options)
# Sempre incluir
json.merge!({
sale_number_formatted: "##{sale_number.to_s.rjust(6, '0')}",
total_formatted: total.to_money.format,
status_label: I18n.t("sale.status.#{status}")
})
# Campos para show
if options[:template] == "show"
json.merge!({
items: items.map(&:as_json),
payments: payments.map(&:as_json),
customer: customer&.as_json(template: "summary")
})
end
# Campos para admins
if current_ability&.can?(:manage, Sale)
json.merge!({
profit: profit.to_f,
cost: cost.to_f
})
end
json
end
end
Com as_json bem configurado, você controla exatamente quais dados são enviados para o frontend. 🧠✨