rails how enum docs application all html ruby-on-rails enums rails-models

html - how - En Rails, ¿cómo debería implementar un campo de estado para una aplicación de tareas-entero o enum?



ruby docs enumerable (6)

Para una aplicación Rails 3.0 Todo, tengo un modelo de tareas con un campo de estado . ¿Cuál es la mejor manera de almacenar los datos del campo de estado (tipo de campo) y aún mostrar una versión legible para los humanos en una vista (tabla HTML)? El estado puede ser:

0 = Normal
1 = Activo
2 = Completado

En este momento tengo esto:

Esquema de carriles aquí:

create_table "tasks",: force => true do | t |
t.integer "estado",: límite => 1,: predeterminado => 0,: nulo => falso

Modelo de rieles aquí:

class Task < ActiveRecord::Base validates_inclusion_of :status, :in => 0..2, :message => "{{value}} must be 0, 1, or 2"

Vista de carriles aquí:

<h1>Listing tasks</h1> <table> <tr> <th>Status</th> <th>Name</th> <th></th> <th></th> <th></th> </tr> <% @tasks.each do |task| %> <tr> <td><%= task.status %></td> <td><%= task.name %></td> <td><%= link_to ''Show'', task %></td> <td><%= link_to ''Edit'', edit_task_path(task) %></td> <td><%= link_to ''Delete'', task, :confirm => ''Are you sure?'', :method => :delete %></td> </tr> <% end %> </table>

Requisitos

  1. Almacene el estado de una Tarea en la base de datos de modo que los valores sean fácilmente localizables, es decir, no estoy seguro de querer almacenar "normal", "activo", "completado" como un campo de cadena.

  2. La solución debe funcionar con Rails 3.0.

Preguntas:

  1. ¿Debo almacenar el campo como un número entero (ver arriba)? De ser así, ¿cómo puedo mostrar el estado correcto legible por humanos en una tabla HTML en mi vista de Rails, por ejemplo, mostrar "Activo" en lugar de "1" en la tabla HTML?

  2. ¿Debo usar una enumeración? Si es así, ¿es fácil localizarlo más tarde?

  3. ¿Debo usar cadenas rectas, por ejemplo, "Normal", "Activa", "Completada"

  4. ¿Puede proporcionar una muestra de código rápido del asistente de visualización, el controlador o el código de vista para que esto funcione?


He usado Enum-Column para tales casos de uso. El complemento le permite definir un tipo de columna enum en su script de migración y crea un tipo de columna enum MYSQL para el atributo.

create_table :tasks do |t| ... t.enum :status, :limit => [:normal, :active, :completed], :default => :normal ... end

Ahora en tu código puedes hacer lo siguiente:

task.status = "active" task.status = :completed p "Task status: #{task.status}" # prints Task status: completed Task.find_by_status(:active) Task.find_by_status("active") Task.find_by_status(2)

Funciona bien con la serialización también:

task.to_xml # will result in status= active instead of status-2

Otro aspecto agradable es que los valores de estado se muestran como cadenas cuando se ven utilizando un cliente de base de datos normal (por ejemplo, consola de comandos mysql o phpMyAdmin)

El complemento proporciona un almacenamiento óptimo y un acceso fácil de usar para los tipos de enumeración.

Advertencia:

El plugin es bastante viejo y no se mantiene. Lo estoy usando extensamente con MySQL DB. Tuve que parchear el código para que funcione en PostgreSQL. Si está utilizando MySQL, este plugin es una buena opción.


Lo más fácil sería almacenar las cadenas reales en el campo en lugar de agregar otra tabla. Dependiendo de su punto de vista, esta es una mala idea ya que su base de datos no estará lo suficientemente normalizada o una gran idea ya que su aplicación ahora es más eficiente para ser normalizada.

Si opta por no hacer eso y mantener los valores en una tabla separada; necesita configurar las relaciones en el modelo.

class Task < ActiveRecord::Base has_one :status end class Status < ActiveRecord::Base belongs_to :tasks end

Entonces en su vista puede hacer referencia al valor por:

<%= task.status %>


Prefiero almacenar "normal", "activo", ... "completado" como cadena en la tabla porque:

  • es auto documentación (por ejemplo, alguien puede ver los datos pero nunca leer el código fuente de Rails)
  • hay poca (si no no) penalización de rendimiento
  • es (aún) fácil de hacer i18n mediante el atributo virtual Rails en el modelo o cualquier capa en otros idiomas

En estos días, tiendo a desacoplar las constantes de Rails de la base de datos tanto como puedo. Siempre hay gente de PHP / MSSQL / ?? DBA a nuestro alrededor (que quizás no amen a Rails tanto como a nosotros ;-)

Entonces, la respuesta no es entera ni enum (sino un varchar ;-)


Sé que esta es una vieja pregunta, pero quería mencionar 2 puntos que provienen de la experiencia, especialmente si alguien está buscando esto ahora (2014 - OQ fue en 2010):

  1. Si está comenzando un nuevo proyecto> Rails 4 (técnicamente ActiveRecord 4) - use Enums - la ruta más eficiente. Especialmente si necesita crear cualquier clase de consultas SQL complicadas más adelante.
  2. Existe una alternativa más: crear un modelo de estado compuesto que contendrá estados para todos sus otros modelos. Conviértalo en un modelo de STI (agregue una columna de tipo); luego, puede crear cosas como OrderStatus <Status o CustomerStatus <Status y su Order y Customer tendrían atributos de status_id. Esto hace que las consultas sean más lentas (!) Y más engorrosas (!); Sin embargo, es posible que desee seguir esta ruta si crea una aplicación que se enviará a un cliente que no tenga experiencia técnica y que necesite algún tipo de habilidad para agrega / elimina estados a través de algo como ActiveAdmin por su propia cuenta en lugar de modificar tu base de código. Esta también es una opción si su capa de datos no puede manejar enumeraciones.

Usar enteros para almacenar el estado es una buena idea. No obstante, creo que el código proporcionado por la respuesta aceptada no es elegante, ya que contamina toda la clase de modelo solo por un atributo.

Mi sugerencia es anular el atributo getter:

def status { 0 => "active", 1 => "inactive" }[read_attribute(:status)] # use the read_attribute method to prevent infinite loop. end

La lógica de transformar el entero en una cadena solo estará en este método getter, por lo que no es necesario ensuciar la clase.


1.Depende de cuánto desea optimizar las consultas en la base de datos.

2. No realmente, AR no lo admite ''out of the box''. # A partir de Rails, 4 enumeraciones son compatibles desde el primer momento .

3.IMHO puede usar cadenas sin una gran penalización de rendimiento (solo recuerde agregar campo a un índice). Haría esto porque es más fácil internacionalizar y mantener. Sin embargo, puede ir con números enteros si necesita un rendimiento adicional.

Puede echar un vistazo a 2 hilos de SO aquí y aquí, donde se debate esto.

4. Si desea mantenerlos como un número entero, así es como puede lograr esto:

class Task << AR::Base NORMAL = 1 ACTIVE = 2 COMPLETED = 3 STATUSES = { NORMAL => ''normal'', ACTIVE => ''active'', COMPLETED => ''completed'' } validates_inclusion_of :status, :in => STATUSES.keys, :message => "{{value}} must be in #{STATUSES.values.join '',''}" # just a helper method for the view def status_name STATUSES[status] end end

y a la vista:

<td><%= task.status_name %></td>

Si desea usar cadenas, es más simple:

STATUSES = [''normal'', ''active'', ''completed''] validates_inclusion_of :status, :in => STATUSES, :message => "{{value}} must be in #{STATUSES.join '',''}"