Collecting hashes in OpenStruct creates a table entry

Why is this (evaluated in the Rails console)

[{:a => :b}].collect {|x| OpenStruct.new(x)}.to_json 

adds a table entry?

 "[{\"table\":{\"a\":\"b\"}}] 

I want only this:

 "[{\"a\":\"b\"}] 

Does this mean that the Rails to_json method handles OpenStruct differently? When I try it in irb it is not there:

 require 'ostruct' [{:a => :b}].collect {|x| OpenStruct.new(x)}.inspect 
+10
ruby ruby-on-rails
source share
6 answers

Use marshal_dump , although this somewhat strikes the goal of converting it to OpenStruct beforehand:

 [{:a => :b}].collect {|x| OpenStruct.new(x).marshal_dump }.to_json => "[{\"a\":\"b\"}]" 

Shorter way:

 [{:a => :b}].to_json "[{\"a\":\"b\"}]" 

Alternatively, you could moneky patch OpenStruct#as_json , as shown in hiroshi's answer:

 require "ostruct" class OpenStruct def as_json(options = nil) @table.as_json(options) end end 
+13
source share

Because @table is an OpenStruct instance variable and the # as_json Object returns a Hash of instance variables .

In my project, I implemented OpenStruct # as_json to override the behavior.

 require "ostruct" class OpenStruct def as_json(options = nil) @table.as_json(options) end end 
+24
source share

I will get around the problem by subclassing OpenStruct as follows:

 class DataStruct < OpenStruct def as_json(*args) super.as_json['table'] end end 

then you can easily convert to JSON like this:

 o = DataStruct.new(a:1, b:DataStruct.new(c:3)) o.to_json # => "{\"a\":1,\"b\":{\"c\":3}}" 

Carefully? Therefore, in answering your question, you should write this instead:

 [{:a => :b}].collect {|x| DataStruct.new(x)}.to_json 

gives you:

 => "[{\"a\":\"b\"}]" 
+8
source share

With ruby ​​2.1.2, you can use the following to get JSON without the root element of the table:

 [{:a => :b}].collect {|x| OpenStruct.new(x).to_h}.to_json => "[{\"a\":\"b\"}]" 
+4
source share

I found that the other answers were a bit confusing, landing here to just figure out how to turn OpenStruct into Hash or JSON. To clarify, you can simply call marshal_dump on OpenStruct .

 $ OpenStruct.new(hello: :world).to_json => "{\"table\":{\"hello\":\"world\"}}" $ OpenStruct.new(hello: :world).marshal_dump => {:hello=>:world} $ OpenStruct.new(hello: :world).marshal_dump.to_json => "{\"hello\":\"world\"}" 

I personally would be incapable of monkey-patch OpenStruct if you do not do this in a subclass, as this may have unintended consequences.

+2
source share
 openstruct_array.map(&:to_h).as_json 
0
source share

All Articles