2010-12-17 8 views
9

Hay una manera de tener una serialización personalizada para campos en rieles, un método que se ejecuta cuando un campo se guarda y se carga para convertir desde/a una cadena que es lo que finalmente se guarda en la base de datos .serialización personalizada para campos en Rails

Específicamente lo que quiero hacer es tener un campo de tipo de símbolo como género, con posibles valores: masculino y femenino que almacene "masculino" y "femenino" en la base de datos. Hay algunas soluciones, como:

def gender 
    read_attribute(:gender).try(:to_sym) 
end 

pero que deja obj.attributes sin cambios, por lo que es una abstracción con fugas.

Respuesta

10

Puede hacerlo en Rails 3.1. El objeto que desea serializar tiene que responder a los métodos load y dump.

Aquí hay un ejemplo de serialización de una cadena en Base64.

class User < ActiveRecord::Base 
    class Base64 
    def load(text) 
     return unless text 
     text.unpack('m').first 
    end 

    def dump(text) 
     [text].pack 'm' 
    end 
    end 

    serialize :bank_account_number, Base64.new 
end 

Para más detalles ver: http://archives.edgerails.info/articles/what-s-new-in-edge-rails/2011/03/09/custom-activerecord-attribute-serialization/index.html

+3

El enlace de detalles parece estar muerto ahora, desafortunadamente. ¿Hubo alguna razón por la que definiste 'dump' y' load' como métodos de instancia, y pasaste una nueva instancia a 'serialize'? ¿En oposición a definirlos como métodos de clase y pasar la clase a 'serializar'? Solo trato de entender, gracias! – plainjimbo

+0

Me estoy tomando un tiro salvaje en la oscuridad aquí, pero parece que la serialización ActiveRecord usará cualquier objeto que responda a ': dump' y': load'. Entonces, no. No hay ninguna razón por la cual estos sean métodos de instancia en oposición a los métodos de clase. – RyanScottLewis

0

Usted podría usar el método serialize dentro del modelo. Por favor haga referencia a este enlace: (. Ps palabra clave de búsqueda "serializar" en esa página; D) http://api.rubyonrails.org/classes/ActiveRecord/Base.html

En resumen, se puede hacer esto:

class YourModel < ActiveRecord::Base 
    serialize :db_field 
end 

rieles se serializar automáticamente el campo antes de guardar a la base de datos, y deserializarlo después de recuperarlo de la base de datos.

+1

El problema es que se convierte en yaml, lo que hace que los datos sean más difíciles de usar en las consultas cuando simplemente guardar un símbolo recto para la conversión de cadenas estaría bien. Eso es lo que quise decir al guardar "masculino" y "femenino" en la base de datos, es decir, en lugar de "---: masculino" y "---: femenino"). – Pablo

0

bien para solo hombre/mujer que acaba podría hacer una columna booleana como macho y si era falso suponer que significaba femenino, añadir métodos de contenedor para que

def female? 
    return !self.male? 
end 
+0

Esto es solo un ejemplo, quiero almacenar más de dos símbolos. Pruébalo con masculino, femenino, desconocido y oculto. – Pablo

4
def whachamacallit 
    read_attribute("whachamacallit").to_sym 
end 
def whachamacallit=(name) 
    write_attribute("whachamacallit", name.to_s) 
end 

guardarlas como picaduras en el base de datos, pero extráigalos como símbolos cuando los saque y vuelva a convertir antes de guardar. funcionaría con cualquier número o combinación de cadenas/símbolos.

limitarlo a sólo unos pocos elegidos

validates_inclusion_of :whachamacallit, :in => [ :male, :female, :unknown, :hidden ] 
+0

He considerado esta solución, lo que no me gusta es que si miro obj.attributes, obviamente, el campo es una cadena en lugar de un campo y sé que volverá a afectarme cuando menos lo espero eso. – Pablo

0

Acabamos de lanzar una joya (AttributeHelpers) que hace exactamente esto. Descargo de responsabilidad: soy un mantenedor de la gema.

Le permite llamar al attr_symbol :gender en la definición de su clase y la serialización se produce automágicamente.

Cuestiones relacionadas