views:

732

answers:

2

I have a model that uses a serialized column:

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

Is there a way to make this serialization use JSON instead of YAML?

+3  A: 

Probably this is what you're looking for.

Form.find(:first).to_json

Update

1) Install 'json' gem:

gem install json

2) Create JsonWrapper class

# 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) Add model callbacks:

#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) Test it!

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

PS:

It's not quite DRY, but I did my best. If anyone can fix after_find in User model, it'll be great.

St.Woland
You don't get that. He wants :options attribute to be serialized into json data, not into yaml.
Eimantas
Ja, using serialize, the values in the options field get stored in the database as a YAML-serialized value. I want that to be JSON instead.
Toby Hede
Updated the answer.
St.Woland
A: 

My requirements didn't need a lot of code re-use at this stage, so my distilled code is a variation on the above answer:

  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  

Cheers, quite easy in the end!

Toby Hede