55 votes

ActiveRecord sérialiser en utilisant JSON au lieu de YAML

J'ai un modèle qui utilise une colonne sérialisée:

 class Form < ActiveRecord::Base
  serialize :options, Hash
end
 

Existe-t-il un moyen de faire en sorte que cette sérialisation utilise JSON au lieu de YAML?

157voto

mid Points 1389

Dans Rails 3.1, vous pouvez simplement

 class Form < ActiveRecord::Base
  serialize :column, JSON
end
 

J'espère que cela pourra aider

58voto

balu Points 1960

Dans les Rails 3.1 vous pouvez utiliser des codeurs avec serialize.

class ColorCoder
  # Called to deserialize data to ruby object.
  def load(data)
  end

  # Called to convert from ruby object to serialized data.
  def dump(obj)
  end
end

class Fruits < ActiveRecord::Base
  serialize :color, ColorCoder.new
end

Espérons que cette aide.

Références:

Définition de l' serialize: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/base.rb#L556

La valeur par défaut YAML codeur qui est livré avec des rails: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/coders/yaml_column.rb

Et c'est là que l'appel à l' loadqui se passe: https://github.com/rails/rails/blob/master/activerecord/lib/active_record/attribute_methods/read.rb#L132

11voto

St.Woland Points 3574

Mise à jour

Voir le milieu de la haute note de réponse ci-dessous pour un beaucoup plus approprié Rails >= 3.1 réponse. C'est une excellente réponse pour les Rails < 3.1.

C'est probablement ce que vous cherchez.

Form.find(:first).to_json

Mise à jour

1) Installer 'json' gem:

gem install json

2) Créer JsonWrapper classe

# lib/json_wrapper.rb

require 'json'
class JsonWrapper
  def initialize(attribute)
    @attribute = attribute.to_s
  end

  def before_save(record)
    record.send("#{@attribute}=", JsonWrapper.encrypt(record.send("#{@attribute}")))
  end

  def after_save(record)
    record.send("#{@attribute}=", JsonWrapper.decrypt(record.send("#{@attribute}")))
  end

  def self.encrypt(value)
    value.to_json
  end

  def self.decrypt(value)
    JSON.parse(value) rescue value
  end
end

3) Ajouter le modèle rappels:

#app/models/user.rb

class User < ActiveRecord::Base
    before_save      JsonWrapper.new( :name )
    after_save       JsonWrapper.new( :name )

    def after_find
      self.name = JsonWrapper.decrypt self.name
    end
end

4) Tester!

User.create :name => {"a"=>"b", "c"=>["d", "e"]}

PS:

Ce n'est pas tout à fait SEC, mais j'ai fait de mon mieux. Si quelqu'un peut résoudre after_find en User modèle, ça va être génial.

8voto

Toby Hede Points 22128

Mes exigences n'ayant pas nécessité beaucoup de réutilisation de code à ce stade, mon code distillé est une variante de la réponse ci-dessus:

   require "json/ext"

  before_save :json_serialize  
  after_save  :json_deserialize


  def json_serialize    
    self.options = self.options.to_json
  end

  def json_deserialize    
    self.options = JSON.parse(options)
  end

  def after_find 
    json_deserialize        
  end  
 

Salut, assez facile à la fin!

3voto

caribu Points 31

La méthode serialize :attr, JSON utilisant composed_of fonctionne comme suit:

   composed_of :auth,
              :class_name => 'ActiveSupport::JSON',
              :mapping => %w(url to_json),
              :constructor => Proc.new { |url| ActiveSupport::JSON.decode(url) }
 

où url est l'attribut à sérialiser à l'aide de json et auth est la nouvelle méthode disponible sur votre modèle qui enregistre sa valeur au format json dans l'attribut url. (pas encore complètement testé mais semble fonctionner)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X