Pular para o conteúdo principal

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 CampoFormato no JSON
:moneyConvertido para Float via .to_f
:dateFormato ISO 8601
:date_timeFormato ISO 8601 com timezone
*_id (relacionamento)ID como String + campo *_id_label
*_ids (relacionamento múltiplo)Array de IDs como Strings
:dropzone, :fileArray com URLs
OutrosValor 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çãoUso
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 merge para 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 includes no 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. 🧠✨