Imagine um caso onde você esteja implementando um sistema de questões e sua entidade precisa ter os status “pendente”, “aprovada” ou “rejeitada”. Ou um número de telefone que pode ser fixo, celular ou fax (se você estiver em 1980). Alguns models têm esse requisito onde um atributo pode assumir somente um conjunto fixo de valores. Você poderia criar um model à parte e adicionar a relação belongs_to entre o status e a questão, mas é um esforço adicional para uma tarefa trivial. A partir do Rails 4.1, você pode utilizar o enumerador do ActiveRecord.
A utilização do enums do ActiveRecord é bem simples. A coluna que você vai utilizar deve ter o tipo inteiro:
1 |
rails g model Question description:text status_question:integer |
É necessário também adicionar ao arquivo do model a listagem dos possíveis valores que o atributo pode assumir:
1 2 3 |
class Question < ActiveRecord::Base enum status_question: [:pending, :approved, :rejected] end |
E agora, quando você acessar o valor do atributo, em vez de receber o valor inteiro armazenado no banco, receberá a string correspondente:
1 2 |
irb(main):002:0> Question.first.status_question => "pending" |
E para atribuir, pode utilizar ambos string ou inteiro:
1 2 3 4 5 6 |
irb(main):003:0> question.status_question = 0; question.status_question => "pending" irb(main):004:0> question.status_question = "pending"; question.status_question => "pending" |
Ou ainda utilizar o método bang:
1 2 3 4 5 |
irb(main):005:0> question.approved! => true irb(main):006:0> question.status_question => "approved" |
O enums também adiciona métodos booleanos para checagem de cada valor da lista:
1 2 3 |
irb(main):007:0> question.approved? => true |
Você também pode acessar a lista de objetos que contém determinado valor (como um escopo):
1 2 3 |
irb(main):008:0> Question.rejected Question Load (0.3ms) SELECT "questions".* FROM "questions" WHERE "questions"."status_question" = ? [["status_question", 2]] |
Se você quiser obter uma lista dos atributos/valores (para usar em uma collection, por exemplo):
1 2 3 |
irb(main):009:0> Question.status_questions => {"pending"=>0, "approved"=>1, "rejected"=>2} |
Alguns pontos importantes
Enums também tem seus cuidados em sua utilização, claro. Quando você define um enum, a ordem importa. Então se você voltar ao seu model, e rearranjá-los em ordem alfabética, por exemplo, seus valores armazenados no banco ficarão inconsistentes. Se ainda assim você decidir que é importante reorganizar, você pode apontar qual o valor inteiro correspondente:
1 2 3 |
class Question < ActiveRecord::Base enum status_question: {approved: 1, pending: 0, rejected: 2} end |
Outro ponto importante é quando você trabalha com esses dados fora da sua aplicação Rails. No seu banco, esses valores estão armazenados como inteiros e não são legíveis sem a associação que você criou. Se a sua aplicação vai crescer a ponto de haver essa necessidade, então o mais recomendado é de fato a sugestão inicial de criar um novo model StatusQuestion para armazenar esses valores, mas em casos mais simples o enums é uma opção de implementação mais simples. Quaisquer dúvidas ou sugestões, utilize a área de comentários ou entre em contato!
1 Comentário
Sannytet
12 de dezembro de 2018 at 03:28Nice posts! 🙂
___
Sanny