ruby-on-rails - form_with - select rails helper
Cómo almacenar y comparar: símbolos en un ActiveRecord(Ruby on Rails) (7)
Pensé que sería bueno rellenar un campo de estado en una tablaRegistro activo usando constantes. Sin embargo, cuando se trata de verificar si este estado tiene un estado particular, estoy teniendo problemas.
Si hago lo siguiente,
e = Mytable.new
e.status = :cancelled
e.save
luego reajusta el registro e intenta comparar mi estado con el símbolo, la verificación falla. Tengo algo de salida de la consola para mostrar esto.
irb(main):060:0> e.status.eql?("cancelled")
=> true
irb(main):061:0> e.status.eql?(:cancelled)
=> false
irb(main):062:0> e.status == :cancelled
=> false
irb(main):063:0> e.status == "cancelled"
=> true
irb(main):064:0> e.status == :cancelled.to_s
=> true
¿Hay una mejor manera de mantener un estado en un registro? ¿Hay alguna manera de probar si un valor de campo actual es igual al símbolo: sin convertir el símbolo: en una cadena? Estoy pensando que puede haber un operador del que no estoy al tanto.
A partir de Rails 4.1, Active Record ahora admite enumeraciones
2.5 Enumeraciones de registros activos
Declare un atributo enum donde los valores se correlacionan con enteros en la base de datos, pero se puede consultar por nombre.
class Conversation < ActiveRecord::Base
enum status: [ :active, :archived ]
end
conversation.archived!
conversation.active? # => false
conversation.status # => "archived"
Conversation.archived # => Relation for all archived Conversations
Conversation.statuses # => { "active" => 0, "archived" => 1 }
Documentación adicional aquí: http://api.rubyonrails.org/v4.1.0/classes/ActiveRecord/Enum.html
A pedido de Ecoologic, aquí está mi comentario como respuesta:
ecoologic tiene una buena solución para usted, pero le recomendaría que se aparte de esto y realice una clase con constantes. Que puede hacer cosas como e.status = Estados :: CANCELADO. E internamente eso podría ser una cadena y no importa. Todavía está usando constantes, y se equivocará si esa constante no existe, y es más limpia de esa manera.
Con Rails 4.1.0, probablemente quiera utilizar enums de Active Record.
Para citar las notas oficiales de la versión :
class Conversation < ActiveRecord::Base
enum status: [ :active, :archived ]
end
conversation.archived!
conversation.active? # => false
conversation.status # => "archived"
Conversation.archived # => Relation for all archived Conversations
Conversation.statuses # => { "active" => 0, "archived" => 1 }
Desde Programming Ruby 1.9 , con respecto al operador == en la clase Symbol (página 729):
Returns true only if sym and obj are symbols with the same object_id.
Todo lo que haya almacenado en la base de datos tendrá siempre diferente object_id que el object_id fijo del símbolo (un puntero a una cadena literal, en este caso).
Esto es algo tarde, pero puede ayudar a alguien más.
Si tiene clases con diferentes estados, puede considerar un enfoque que use constantes junto con ámbitos como este:
class Account < ActiveRecord::Base
#-------------------------------------------------------------------------------
# Configuration
#-------------------------------------------------------------------------------
# STATUS is used to denote what state the account is in.
STATUS = { :active => 1, :suspended => 2, :closed => 3 }
# Scopes
scope :active, where(:status => Account::STATUS[:active])
scope :suspended, where(:status => Account::STATUS[:suspended])
scope :closed, where(:status => Account::STATUS[:closed])
...
end
Luego puede encontrar fácilmente registros basados en el estado, de esta manera:
# get all active accounts
active_accounts = Consumer.active.all
# get 50 suspended accounts
suspended_accounts = Consumer.suspended.limit(50)
# get accounts that are closed and [some search criteria]
closed_accounts = Consumer.closed.where([some search criteria])
¡Espero que esto ayude a alguien más!
EDITAR: Si te gusta más el uso de gemas, la gema simple_enum parece una excelente alternativa.
Si recuerdo bien, los símbolos en ActiveRecord se almacenan en formato yaml, se debe hacer algún tipo de conversión porque no existe un símbolo en db relacional (que conozco, al menos). Cuando lo lees, es una cadena que no coincidirá con tu símbolo y ni siquiera la cadena del símbolo, de hecho, debería ser algo así como:
:x # => "--- :x/n"
Creo que este complemento puede resolver su problema, pero no lo he usado honestamente. https://github.com/zargony/activerecord_symbolize
* EDIT *
Dejo lo anterior porque recuerdo que esa era la situación que tenía y que puedo corregirme si estoy equivocado, sin embargo, estoy intentando esto ahora y el valor almacenado (Rails 3.1.3) es una cadena simple con el valor de el símbolo, entonces lo siguiente debería ser suficiente.
class Example < ActiveRecord::Base
def aaa
super.to_sym
end
def aaa=(value)
super(value.to_sym)
aaa
end
end
Esto, por supuesto, obligará al valor a ser siempre un símbolo
** EDITAR DESPUÉS DE EDADES ** Creo que está bien en esta situación, ya que está claro que en el DB es una cadena y la lógica es simple, pero desaconsejo totalmente anular los métodos de atributos de DB para agregar lógica más compleja.
También puede sobrescribir el método del reader
:
def status
read_attribute(:status).to_sym
end