2010-12-17 3 views
9

Existe-t-il un moyen d'avoir une sérialisation personnalisée pour les champs dans les rails, une méthode qui s'exécute lorsqu'un champ est enregistré et chargé pour convertir de/vers une chaîne qui est finalement enregistrée dans la base de données . Concrètement, ce que je veux faire, c'est avoir un champ de type symbole comme genre, avec des valeurs possibles: male et: female stockant "male" et "female" sur la base de données. Il y a quelques solutions de contournement, comme:Sérialisation personnalisée pour les champs dans Rails

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

mais qui laisse obj.attributes inchangé, il est donc une abstraction qui fuit.

Répondre

10

Vous pouvez le faire dans Rails 3.1. L'objet que vous voulez sérialiser doit répondre aux méthodes load et dump.

Voici un exemple de sérialisation d'une chaîne dans 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 

Pour plus de détails: http://archives.edgerails.info/articles/what-s-new-in-edge-rails/2011/03/09/custom-activerecord-attribute-serialization/index.html

+3

Le lien détails semble être mort maintenant, malheureusement. Y a-t-il une raison pour laquelle vous avez défini 'dump' et' load' comme des méthodes d'instance, et passez une nouvelle instance dans 'serialize'? Au lieu de les définir comme méthodes de classe et de passer la classe en «serialize»? J'essaie juste de comprendre, merci! – plainjimbo

+0

Je suis en train de prendre une photo sauvage dans le noir, mais il semble que la sérialisation d'ActiveRecord utilisera n'importe quel objet répondant à ': dump' et': load'. Donc non. Il n'y a aucune raison pour que ce soient des méthodes d'instance par opposition aux méthodes de classe. – RyanScottLewis

0

vous pouvez définir les modèles to_xml pour un modèle et il fera que http://api.rubyonrails.org/classes/ActiveRecord/Serialization.html

il est possible de définir et de mettre en Marshall.dump cette façon, je pense, mais son quelque chose à regarder dans

+0

Je ne parle pas de sérialiser un modèle entier en chaîne, mais de sérialiser un seul champ en une chaîne à stocker dans la base de données. – Pablo

0

Vous pourrait utiliser la méthode serialize à l'intérieur du modèle. S'il vous plaît référence à ce lien: (. Ps mot-clé de recherche "sérialisation" dans cette page; D) http://api.rubyonrails.org/classes/ActiveRecord/Base.html

En bref, vous pouvez le faire:

class YourModel < ActiveRecord::Base 
    serialize :db_field 
end 

Rails seraient automatiquement sérialiser le champ avant d'enregistrer à la base de données et désérialiser après l'extraction de la base de données.

+1

Le problème avec cela est qu'il convertit en yaml, ce qui rend les données plus difficiles à utiliser dans les requêtes quand il suffit d'enregistrer un symbole droit à la conversion de chaîne serait bien. C'est ce que j'ai voulu dire en sauvant "male" et "female" dans la base de données, c'est-à-dire, au lieu de "---: male" et "---: female"). – Pablo

0

bien pour tout homme/femme vous pouvez simplement faire une colonne booléenne comme mâle et si elle était fausse supposer que des femmes signifiait, ajouter des méthodes wrapper pour elle

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

Ceci est juste un exemple, je veux stocker plus de deux symboles. Essayez-le avec un homme, une femme, inconnu et caché. – Pablo

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

les stocker sous forme piqûres dans la base de données, mais les extraire comme des symboles lorsque vous les sortez puis convertir avant de sauvegarder. fonctionnerait avec n'importe quel nombre ou combinaison de chaînes/symboles.

à limiter à seulement quelques privilégiés

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

J'ai considéré cette solution, ce que je n'aime pas c'est que si je regarde obj.attributes le champ est évidemment une chaîne au lieu d'un champ et je sais qu'il reviendra me mordre quand je m'attendais moins il. – Pablo

0

Nous venons de publier un petit bijou (AttributeHelpers) qui fait exactement cela. Disclaimer: Je suis un mainteneur pour la gemme.

Il vous permet d'appeler attr_symbol :gender dans votre définition de classe et la sérialisation se produit automagiquement.

Questions connexes