在嵌套对象中使用自定义to_json方法 [英] Using custom to_json method in nested objects
问题描述
我有一个数据结构,该数据结构使用Ruby标准库中的Set类.我希望能够将我的数据结构序列化为JSON字符串.
I have a data structure that uses the Set class from the Ruby Standard Library. I'd like to be able to serialize my data structure to a JSON string.
默认情况下,Set序列化为数组:
By default, Set serializes as an Array:
>> s = Set.new [1,2,3]
>> s.to_json
=> "[1,2,3]"
在您尝试对其进行反序列化之前,还可以.
Which is fine until you try to deserialize it.
所以我定义了一个自定义的to_json
方法:
So I defined a custom to_json
method:
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,2,3]
>> s.to_json
=> "{\"data\":{\"elements\":[1,2,3]},\"json_class\":\"Set\"}"
直到我将Set放入哈希或其他内容之前:
Until I put the Set into a Hash or something:
>> a = { 'set' => s }
>> a.to_json
=> "{\"set\":[1,2,3]}"
有人知道为什么Set嵌套在另一个对象中时为什么我的自定义to_json
没有被调用吗?
Any idea why my custom to_json
doesn't get called when the Set is nested inside another object?
推荐答案
第一个块用于Rails 3.1(旧版本几乎相同);第二个块用于标准的非Rails JSON.如果是tl; dr,则跳到最后.
The first chunk is for Rails 3.1 (older versions will be pretty much the same); the second chunk is for the standard non-Rails JSON. Skip to the end if tl;dr.
您的问题是Rails会这样做:
Your problem is that Rails does this:
[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
.特别是,这会将Hash的 in 然后,查看 Then, looking at 因此,所有的Rails JSON编码都通过 So all the Rails JSON encoding goes through 如果您设置自己的 然后,您将在Rails控制台和一般的Rails中得到想要的东西: then you'll get what you're after in the Rails console and Rails in general: 请记住, Keep in mind that 当我们查看标准的非Rails JSON库时,我们会看到类似这样的内容: When we look at the standard non-Rails JSON library, we see things like this: 猴子已打入基本类(符号,时间,日期等)中.再次重申,通常用 monkey patched into the basic classes (Symbol, Time, Date, ...). So once again, 并且我们为解码器提供了您的 And we include your
执行摘要:如果您在Rails中,不必担心使用
Executive Summary: If you're in Rails, don't worry about doing anything with 这篇关于在嵌套对象中使用自定义to_json方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!to_json
方法更改为仅一个ActiveSupport::JSON.encode
调用.active_support/core_ext/object/to_json.rb
. In particular, that changes Hash's to_json
method into just an ActiveSupport::JSON.encode
call.ActiveSupport::JSON::Encoding::Encoder
,我们看到以下内容:ActiveSupport::JSON::Encoding::Encoder
, we see this: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
as_json
进行.但是,您并没有为Set定义自己的as_json
,而是只是设置to_json
,并且当Rails忽略它不使用的内容时会感到困惑.as_json
. But, you're not defining your own as_json
for Set, you're just setting up to_json
and getting confused when Rails ignores something that it doesn't use.Set#as_json
:class Set
def as_json(options = { })
{
"json_class" => self.class.name,
"data" => { "elements" => self.to_a }
}
end
end
> require 'set'
> s = Set.new([1,2,3])
> s.to_json
=> "{\"json_class\":\"Set\",\"data\":{\"elements\":[1,2,3]}}"
> h = { :set => s }
> h.to_json
=> "{\"set\":{\"json_class\":\"Set\",\"data\":{\"elements\":[1,2,3]}}}"
as_json
用于准备要进行JSON序列化的对象,然后to_json
会生成实际的JSON字符串. as_json
方法通常返回简单的可序列化的数据结构,例如Hash和Array,并在JSON中具有直接类似物.然后,一旦有了类似JSON的结构,就可以使用to_json
将其序列化为线性JSON字符串.as_json
is used to prepare an object for JSON serialization and then to_json
produces the actual JSON string. The as_json
methods generally return simple serializable data structures, such as Hash and Array, and have direct analogues in JSON; then, once you have something that is structured like JSON, to_json
is used to serialize it into a linear JSON string.def to_json(*a)
as_json.to_json(*a)
end
as_json
来实现to_json
.在这种环境中,我们需要包括标准的to_json
以及上面的as_json
集合:to_json
is generally implemented in terms of as_json
. In this environment, we need to include the standard to_json
as well as the above 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
中获得类似的信息:json_create
class method for the decoder. Once that's all properly set up, we get things like this in irb
:>> s = Set.new([1,2,3])
>> s.as_json
=> {"json_class"=>"Set", "data"=>{"elements"=>[1, 2, 3]}}
>> h = { :set => s }
>> h.to_json
=> "{"set":{"json_class":"Set","data":{"elements":[1,2,3]}}}"
to_json
做任何事情,as_json
是您想玩的东西.如果您不在Rails中,请在as_json
中实现大部分逻辑(尽管文档中有说明),并添加标准的to_json
实现(def to_json(*a);as_json.to_json(*a);end
).
to_json
, as_json
is what you want to play with. If you're not in Rails, implement most of your logic in as_json
(despite what the documentation says) and add the standard to_json
implementation (def to_json(*a);as_json.to_json(*a);end
) as well.