ruby – 在嵌套对象中使用custom to_json方法

前端之家收集整理的这篇文章主要介绍了ruby – 在嵌套对象中使用custom to_json方法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个使用 Ruby标准库中的Set类的数据结构.我想能够将我的数据结构序列化为JSON字符串.

默认情况下,将序列化为数组:

>> s = Set.new [1,2,3]
>> s.to_json
=> "[1,3]"

在你尝试反序列化之前,这是很好的.

所以我定义了一个自定义的to_json方法

class Set
  def to_json(*a)
    {
      "json_class" => self.class.name,"data" => {
        "elements" => self.to_a
      }
    }.to_json(*a)
  end

  def self.json_create(o)
    new o["data"]["elements"]
  end
end

哪个工作很好

>> s = Set.new [1,3]
>> s.to_json
=> "{\"data\":{\"elements\":[1,3]},\"json_class\":\"Set\"}"

直到我把The Set放入哈希或其他东西:

>> a = { 'set' => s }
>> a.to_json
=> "{\"set\":[1,3]}"

任何想法为什么当Set嵌套在另一个对象中时,我的自定义to_json不会被调用

解决方法

第一块是Rails 3.1(旧版本几乎相同);第二个块是用于标准的非Rails JSON.如果tl; dr.跳到最后

你的问题是Rails这样做:

[Object,Array,FalseClass,Float,Hash,Integer,NilClass,String,TrueClass].each do |klass|
  klass.class_eval <<-RUBY,__FILE__,__LINE__
    # Dumps object in JSON (JavaScript Object Notation). See www.json.org for more info.
    def to_json(options = nil)
      ActiveSupport::JSON.encode(self,options)
    end
  RUBY
end

在active_support / core_ext / object / to_json.rb中.特别是,将Hash的to_json方法更改为ActiveSupport :: JSON.encode调用.

然后,看看ActiveSupport :: JSON :: Encoding :: Encoder,我们看到:

def encode(value,use_options = true)
  check_for_circular_references(value) do
    jsonified = use_options ? value.as_json(options_for(value)) : value.as_json
    jsonified.encode_json(self)
  end   
end

所以所有的Rails JSON编码都经过as_json.但是,您没有为Set定义自己的as_json,只是设置to_json并在Rails忽略它不使用的东西时变得困惑.

如果你设置自己的Set#as_json:

class Set
    def as_json(options = { })
        {
            "json_class" => self.class.name,"data" => { "elements" => self.to_a }
        }
    end
end

那么您将在Rails控制台和Rails中获得您的一切:

> require 'set'
> s = Set.new([1,3])
> s.to_json
 => "{\"json_class\":\"Set\",\"data\":{\"elements\":[1,3]}}"
> h = { :set => s }
> h.to_json
 => "{\"set\":{\"json_class\":\"Set\",3]}}}"

请记住,as_json用于准备JSON序列化的对象,然后to_json生成实际的JSON字符串. as_json方法通常返回简单的可序列化数据结构,例如Hash和Array,并且在JSON中具有直接的类似性;那么,一旦你有一些像JSON这样的结构,那么to_json就被用来将其序列化成一个线性的JSON字符串.

当我们看标准的非Rails JSON库时,我们会看到如下所示的内容

def to_json(*a)
  as_json.to_json(*a)
end

猴子修补了基础课(符号,时间,日期,…).所以再次,to_json通常是以as_json来实现的.在这种环境中,我们需要包含标准的to_json以及上面的as_json for Set:

class Set
    def as_json(options = { })
        {
            "json_class" => self.class.name,"data" => { "elements" => self.to_a }
        }
    end
    def to_json(*a)
        as_json.to_json(*a)
    end
    def self.json_create(o)
        new o["data"]["elements"]
    end
end

并且我们将json_create类方法包含在解码器中.一旦这样做完全正确,我们在irb中得到这样的东西:

>> s = Set.new([1,3])
>> s.as_json
=> {"json_class"=>"Set","data"=>{"elements"=>[1,3]}}
>> h = { :set => s }
>> h.to_json
=> "{"set":{"json_class":"Set","data":{"elements":[1,3]}}}"

执行摘要:如果你在Rails,不用担心做任何事情to_json,as_json是你想玩的东西.如果你不在Rails中,在as_json中实现大部分的逻辑(尽管文档说明了),并添加了标准的to_json实现(def to_json(* a); as_json.to_json(* a); end).

猜你在找的Ruby相关文章