Skip to content
novembro 11, 2008 / cassiomarques

simulando enums em classes Ruby

Algo que sempre faço é evitar criar tabelas no banco de dados apenas para cadastrar coisas como “os status possíveis de um cliente” ou “os tamanhos possíveis de um item” ou qualquer outra coisa parecida. Acho que esses controles devem estar na aplicação, uma vez que a lógica da aplicação depende desses valores. Banco de dados não deve ter lógica, deve ser usado apenas para guardar dados.
Quando programo em Java, recorro às Enums para me ajudar nesta tarefa. Crio lá uma enum, declaro os possíveis valores e depois digo que determinado atributo da minha classe é um elemento da tal enum. Funciona legalzinho e não preciso ficar criando tabelas com 5 linhas cujos valores não-mudam-nunca-mais-na-vida.

Mas e no Ruby/Rails, como fazer? Não, não existem enums no Ruby. Pelo menos não “out-of-the-box”, você teria que criar algo… Acontece que para a maioria dos (meus) casos, a solução acaba sendo mais simples do que isso…

Suponha uma classe Fatura que possui um atributo status, cujos valores podem ser “Emitida”, “Recebida” e “Vencida”. A solução que costumo adotar é mais ou menos assim:

class Fatura < ActiveRecord::Base
  EMITIDA = 1
  RECEBIDA = 2
  VENCIDA = 3
  
  Status = {
    EMITIDA => "Emitida",
    RECEBIDA => "Recebida",
    VENCIDA => "Vencida"  
  }
  
  def status_str
    Status[self.status]
  end
end

E isso resolve. Só tem um problema: Esse código ainda está um pouco feio, tem repetição desnecessária ai. Tá vendo que eu declaro as constantes e depois escrevo tudo de novo dentro do hash onde crio as strings com as descrições de cada status? Pois é… dá pra simplificar isso ai! Conhecendo um pouco sobre precedência de operadores em Ruby, dá pra fazer com que as contantes sejam criadas e ao mesmo tempo utilizemos estes valores como chaves no nosso hash com as strings, assim:

class Fatura < ActiveRecord::Base
  Status = {
    (EMITIDA = 1) => "Emitida",
    (RECEBIDA = 2) => "Recebida",
    (VENCIDA = 3) => "Vencida"  
  }
  
  def status_str
    Status[self.status]
  end
end

Agora o código ficou mais simples e você pode usar assim:

f = Fatura.new
f.status = Fatura::EMITIDA
puts f.status_str # => "Emitida"

Existe uma certa discussão sobre fazer coisas como o que mostrei acima. Por um lado tenta-se manter o código com o mínimo de repetição possível. Por outro, tenta-se mantê-lo o mais legível possível. Às vezes você vai ter que sacrificar um pouco de um destes fatores para ter melhorias em relação ao outro. IMHO eu não considero o mostrado acima como algo que sacrifica a legibilidade do código, pelo contrário. Mas sei que há controvérsias…

10 Comentários

Deixe um comentário
  1. Éverton Ribeiro / nov 12 2008 5:32 am

    Cássio,

    Na mesma linha de raciocínio, mas com uma solução um pouco diferente existe esse plugin: http://github.com/zargony/activerecord_symbolize/tree, que usa símbolos no lugar de constantes.

    Inclusive eu fiz algumas alterações nele, que adicionam validação automática dos valores possíveis, e helpers que criam selects e radiobuttons para escolha nos formulários: http://github.com/nuxlli/activerecord_symbolize

  2. cassiomarques / nov 12 2008 1:10 pm

    Muito bacana Éverton, eu não conhecia esse plugin. Vou dar uma olhada, obrigado!

  3. cassiomarques / nov 12 2008 1:16 pm

    Éverton, dei uma olhada lá, bem bacana a solução. A vantagem que eu vejo é a garantia de que valores inválidos não serão aceitos. A princípio a única desvantagem é que os valores ficam guardados no banco na forma de strings, o que pode ser um pouco menos performático do que integers para realização de buscas.
    Achei bem legal também os helpers para radio e select. Eu costumo criá-los aqui com um esqueminha que tenho, mas não cheguei a transformar em plugin nem nada…
    Será que dá pra colocar suporte a integers nesse plugin que você me passou?
    Abraço!

  4. Murilo Adriano / nov 14 2008 6:33 pm

    Olá Cássio, parabéns pelo seu blog!

    Segundo o WP é um dos que crescem mais rapidamente. Parabéns!
    Gostaria de saber como faz para colocar esse code highlighter no WordPress.
    Está convidado a ler o meu blog também :P

    Obrigado cara.
    Abraço!

  5. cassiomarques / nov 14 2008 7:28 pm

    Olá Murilo, obrigado pelo apoio!

    Eu até entraria no seu blog, mas sabe o que é… você não deixou o endereço!

    Para colocar syntax highlight no código é facil: Quando vc estiver criando um novo post, no modo HTML você faz:

    Coloca seu código aqui dentro

    e pronto! Troca o “blablabla” pelo nome da linguagem na qual seu código está escrito.

    Abraço!

  6. Flávio Granero / nov 17 2008 4:26 pm

    Olá Cássio, boa dica sobre o uso de Enums no Rails. Existe outra alternativa que eu costumo usar que é o plugin Enum_fu (http://github.com/ikspres/enum_fu/). É bem simples e ele armazenas em campos integer no DB.

    Abraço.

  7. cassiomarques / nov 17 2008 4:31 pm

    Olá Flávio,

    Depois deste post eu descobri o active_record_symbolize *http://github.com/zargony/activerecord_symbolize) e estou usando-o. Uma coisa boa desse Enum_fu que você citou é que ele grava tudo como inteiro no banco, isso é legal.
    Abraço!

  8. akantos / maio 23 2012 11:39 pm

    Solução show de bola! Vi que a galera indicou plugins mas acredito que quanto mais dependências teu aplicativo têm, maior será o risco de enfrentamento do inferno do controle de versões de componentes e suas incompatibilidades durante migrações. Xô! Fico com tua solução! Abs

    • cassiomarques / maio 23 2012 11:44 pm

      Interessante seu comentário :) Esse post é bastante velho (3 anos e meio!) e de lá prá cá passei a adotar soluções que considero ainda melhores para esse problema. Desenvolvi uma gem chamada EnumerateIt para lidar com isso, que provê diversas funcionalidades que talvez você considere interessantes.

      https://github.com/cassiomarques/enumerate_it

      Quanto a problemas de incompatibilidade, não se preocupe. A gem é relativamente simples e praticamente não depende do Rails (apesar de existir uma camada – opcional – de integração ao ActiveRecord).

Trackbacks

  1. nuxlli » Novo atributo *_humanize no plugin activerecord_symbolize

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: