/* CODIFICANDO */

Relatos de um programador em contínua aprendizagem.

simulando enums em classes Ruby

com 8 comentários

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…

Escrito por cassiomarques

Novembro 11, 2008 às 10:03 pm

Publicado em ruby

Etiquetado com

8 Respostas

Subscreva aos comentários comRSS.

  1. 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

    Éverton Ribeiro

    Novembro 12, 2008 em 5:32 am

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

    cassiomarques

    Novembro 12, 2008 em 1:10 pm

  3. É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!

    cassiomarques

    Novembro 12, 2008 em 1:16 pm

  4. 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!

    Murilo Adriano

    Novembro 14, 2008 em 6:33 pm

  5. 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!

    cassiomarques

    Novembro 14, 2008 em 7:28 pm

  6. [...] Cássio do /* CODIFICANDO */, fez um post dando uma dica de como simular uma funcionalidade de enum no ActiveRecord, para trabalhar com uma [...]

  7. 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.

    Flávio Granero

    Novembro 17, 2008 em 4:26 pm

  8. 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!

    cassiomarques

    Novembro 17, 2008 em 4:31 pm


Deixe uma resposta