Reputation: 48511
I spent last couple of hours of trying to manually (without Active Record to create a structure like this, taken from an API's documentation:
params_map = '{ "field1" => {"field1a"=>"some text"},
"field2" => {
"field2a" => "a",
"field2b" => "b",
"field2c" => "c",
"field2d" => {"field2d_a" => "2d_a"},
"field2e" => "e",
"items" => [
{ "items_a" => "1",
"items_b" => "2",
"items_c" => "3",
"items_d" => "4"
},
{ "items_e" => "5",
"items_f" => "6",
"items_g" => "7",
"items_h" => "8"
}]
},
"field3" => "field3 text",
"field4" => "field4 text"}'
params_map_eval = eval(params_map)
How can I create this in Ruby? I tried to create it as a Hash using Hash.new
, also as a JSON, but I failed at adding/appending another fields to the big JSON.
The items
will be a loop and I'll populate it from database, but how do I create this structure in Ruby?
Upvotes: 7
Views: 26742
Reputation: 523
By far the easiest way is to simply create a hash with a similar structure to the JSON, and then simply call .to_json on that hash. You don’t need to do any error-prone/XSS-risky string concatenation to manually create the JSON.
You can use all of the Ruby language to generate your hash, including loops, mapping, variables, merging hashes, string interpolation, etc.
Once the hash has the same structure as the JSON, then just call .to_json on it, and voila, you have valid JSON-encoded version of the hash.
As long as the data types you use in your hashes are valid JSON “primitive”, i.e. nil, strings, numbers, arrays, and other hashes, and all the hash keys are strings (or symbols), or numbers, this should create a 1:1 mapping of Ruby hash to JSON hash.
To generate the above example given in the original post, you could build the hash like so:
params_map = {}
params_map[:field1] = { :field1a => 'some_text' }
params_map[:field2] = { :field2a => 'a', :field2b => 'b', :field2c => 'c' }
params_map[:field2][:field2d] = { :field2d_a => '2d_a' }
params_map[:field2][:field2e] = :e
items =
[{ :items_a => "1",
:items_b => "2",
:items_c => "3",
:items_d => "4"
}]
items.push({
:items_e => '5',
:items_f => '6',
:items_g => '7'
}.merge('item_h' => "8"))
params_map[:field2][:items] = items
params_map[:field3] = "Field3 text"
params_map.merge!(:field4 => "field4_text")
Notice how I am using different Ruby features to build out the hash.
If you inspect the hash at the end, it will look something like this
>> params_map
=> {:field1=>{:field1a=>"some_text"}, :field2=>{:field2a=>"a", :field2b=>"b", :field2c=>"c", :field2d=>{:field2d_a=>"2d_a"}, :field2e=>:e, :items=>[{:items_a=>"1", :items_b=>"2", :items_c=>"3", :items_d=>"4"}]}, :field3=>"Field3 text"}
You can then simply call params_map.to_json
, JSON.dump(params_map)
, or JSON.pretty_generate(params_map)
on the hash to get the JSON representation of the hash, which will in fact be valid JSON.
>> json = JSON.pretty_generate(params_map) #or use params_map.to_json or JSON.dump(params_map)
>> puts json
{
"field1": {
"field1a": "some_text"
},
"field2": {
"field2a": "a",
"field2b": "b",
"field2c": "c",
"field2d": {
"field2d_a": "2d_a"
},
"field2e": "e",
"items": [
{
"items_a": "1",
"items_b": "2",
"items_c": "3",
"items_d": "4"
},
{
"items_e": "5",
"items_f": "6",
"items_g": "7",
"item_h": "8"
}
]
},
"field3": "Field3 text",
"field4": "field4_text"
}
Then, to make any changes to the JSON, just edit the original params_map
hash using Ruby and call .to_json / JSON.dump / JSON.pretty_generate
again
Upvotes: 2
Reputation: 160631
If you want to create JSON you use the JSON standard-library which comes with Ruby:
require 'json'
foo = {
'a' => 1,
'b' => [2,3]
}
puts JSON[foo]
# >> {"a":1,"b":[2,3]}
If you're trying to figure out how to create a particular JSON output based on a Ruby hash or array, it's easily done by reversing the process and starting with a sample of the desired JSON, and letting the parser turn it into the base object:
JSON['{"a":1,"b":[2,3]}'] # => {"a"=>1, "b"=>[2, 3]}
To modify an existing JSON string, parse it into a Ruby object, modify that, then output it again:
bar = JSON['{"a":1,"b":[2,3]}']
bar['c'] = 'more data'
puts JSON[bar]
# >> {"a":1,"b":[2,3],"c":"more data"}
It's important to note that your example
params_map = '{ "field1" => {"field1a"=>"some text"},
"field2" => {
"field2a" => "a",
"field2b" => "b",
"field2c" => "c",
"field2d" => {"field2d_a" => "2d_a"},
"field2e" => "e",
"items" => [
{ "items_a" => "1",
"items_b" => "2",
"items_c" => "3",
"items_d" => "4"
},
{ "items_e" => "5",
"items_f" => "6",
"items_g" => "7",
"items_h" => "8"
}]
},
"field3" => "field3 text",
"field4" => "field4 text"}'
is not JSON. It's a string:
foo = '{"a" => 1}'
foo.class # => String
Remove the wrapping '
and you have a hash of hashes:
foo = {"a" => 1, "b" => {"c" => 3}}
foo.class # => Hash
Upvotes: 13
Reputation: 84443
Generally, the right thing to do is to use Hash#merge! or Hash#update to modify the contents of a Ruby hash, and then convert the results to JSON. For example:
require 'json'
# Add items to your Hash object.
params_map = {'field1' => 'foo', 'field2' => 'bar', 'field3' => 'baz'}
params_map.merge! 'field4' => 'quux'
#=> {"field1"=>"foo", "field2"=>"bar", "field3"=>"baz", "field4"=>"quux"}
# Convert Hash object to JSON string.
params_map.to_json
#=> "{\"field1\":\"foo\",\"field2\":\"bar\",\"field3\":\"baz\",\"field4\":\"quux\"}"
Upvotes: 2
Reputation: 1170
You can try with OpenStruct http://ruby-doc.org/stdlib-2.0.0/libdoc/ostruct/rdoc/OpenStruct.html , you can iterate your database and add new key pairs on the fly.
Simple example:
struct = OpenStruct.new
struct.foo = 'bar'
struct.baz = 'biz'
json_struct = struct.to_json
--> {"foo": "bar", "baz": "biz"}
Upvotes: 1
Reputation: 1093
Ruby has a library that you can use to work with JSON files. Doing a simple search in StackOverflow I get this old question.
How to write to a JSON file in the correct format
Good luck!
Upvotes: -2