I'm using json gem in ruby..,My ruby code is here..,
require 'json'
json = JSON.generate [1, 2, [{"pi" => 3.141}, {"integer" => 1234567890}], {"subject" => "Mathematics"}, {"Float"=> 1.324343}, {"number"=> 232132435}]
generator = JSON.parse json
puts generator[2][1]
My key-value pair is working fine.But, I'm trying to print only the key not an value from index[2] such as either an "integer" or "pi".
Is it possible..?
In your case generator[2][1] is a Hash {"integer"=>1234567890}. In order to get all keys from hash you can use Hash#keys method, and then take first (as far as it is the only key in the hash)
generator[2][1].keys.first # => "integer"
You can learn more about Hash methods in this documentation.
Your data structure at generator[2] looks strange, maybe you better use a single Hash for such casese:
{"pi" => 3.141, "integer" => 1234567890} # etc...
Related
I receive (similar to) the following JSON data:
{"accountId"=>"some-private-really-long-account-id",
"stats"=>
{"score"=>
{"globalScore"=>
[{"key"=>"lifetimeScore", "value"=>"571",
"key"=>"someOtherKeyHere", "value"=>"someValue"}]}
I am not quite sure how I would get the lifetime score. I've tried doing stuff like this:
puts data["globalScore"]["lifetimeScore"]["value"]
But that doesn't work. (data is of course the JSON data received).
I believe the problem here is that data["globalScore"]["lifetimeScore"]["value"] doesn't reference a valid "path" within the JSON. Better formatting helps to clarify this:
hash = {
"accountId" => "some-private-really-long-account-id",
"stats" => {
"score" => {
"globalScore" => [
{
"key" => "lifetimeScore",
"value" => "571",
"key" => "someOtherKeyHere",
"value" => "someValue"
}
]
}
}
}
This Ruby hash has some issues since a hash can't actually have multiple values for a given key, but that aside,
hash['stats']['score']['globalScore'][0]['value']
is a perfectly valid way to access the 'value' field.
My point is that the problem with the original question is not that hash#dig(...) should be used (as shown by #Phlip), it is that the "path" through the Hash data structure was actually invalid.
hash.dig("globalScore", "lifetimeScore", "value)
will fail just like the bracketed syntax in the original question.
Use JSON.parse(body) to convert your json to a hash. Then use hash.dig('stats', 'score', 'globalScore', 0, 'value') to run queries on that hash.
So I am iterating through a set of data and building a hash from it:
clean_response = Array.new
response.each_with_index do |h, idx|
clean_response <<
{
:lat => h["location"]["latitude"],
:lg => h["location"]["longitude"],
:place => h["location"]["name"],
#This grabs the entire hash at "location" because we are wanting all of that data
:profile_picture => h["user"]["profile_picture"],
:hash_tags => h["tags"],
:username => h["user"]["username"],
:fullname => h["user"]["full_name"],
:created_time => (Time.at(h["created_time"].to_i)).to_s,
:image => h["images"]["low_resolution"]["url"] # we can replace this with whichever resolution.
}
end
Which return an array of hashes like so:
[{:lat=>40.7486382,
:lg=>-73.9487686,
:place=>"The Cliffs at LIC",
:profile_picture=>"http://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-19/s150x150/12104940_1653775014895036_286845624_a.jpg",
:hash_tags=>["bouldering"],
:username=>"denim_climber",
:fullname=>"DenimClimber",
:created_time=>2015-10-13 22:58:09 -0400,
:image=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/11856571_1062082890510188_611068928_n.jpg"},
{:lat=>40.7459602,
:lg=>-73.9574966,
:place=>"SHI",
:profile_picture=>"http://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-19/11348212_1453525204954535_631200718_a.jpg",
:hash_tags=>["cousins", "suchafunmoment", "johnlennonstyle"],
:username=>"xiomirb",
:fullname=>"Xiomi",
:created_time=>2015-10-13 22:57:21 -0400,
:image=>"https://scontent.cdninstagram.com/hphotos-xaf1/t51.2885-15/s320x320/e35/11375290_1688934151392424_2009781937_n.jpg"}]
I'd like to convert this data to json and then serve it to a specific view.
How can I convert this? I tried the .to_json method but it doesn't return a well formatted one since my UI isn't binding to the data.
You can convert a Ruby hash into JSON using to_json:
require 'json'
your_hash.to_json # gives you a JSON object
But, in your case the data is an array of hashes, but NOT a hash. So, your to_json would not work.
I am not quite sure how you want to do this, but one possibility is to loop through the array of hashes, get each hash and convert that to a JSON object using to_json call (like shown above) and build a new array of JSON objects. This way, you can build an array of JSON objects from an array of hashes.
array_of_json = []
# loop through the array of hashes
clean_response.each do |hash|
array_of_json << hash.to_json
end
array_of_json # array of JSON objects
If by "serve it to a specific view" you mean pass it to a .haml or .erb template, you can pass the array of hashes as is. Both haml and erb will allow you to iterate over the array, and even the hash if you want.
If you mean you want to hand a json string to the browser, #to_json should work fine. Other options are jbuilder or oat when you want to refine what is sent, but to_json should "serve" you well!
I am working on parsing JSON in Ruby. Can someone let me know how to take response.body and post it inside string.
Are there any gems available to sort this information via parsing?
require 'net/http'
require 'json'
uri = URI('https://api.wmata.com/StationPrediction.svc/json/GetPrediction/all')
uri.query = URI.encode_www_form({
# Specify your subscription key
'api_key' => '#',
})
request = Net::HTTP::Get.new(uri.request_uri)
# Basic Authorization Sample
# request.basic_auth 'username', 'password'
response = Net::HTTP.start(uri.host, uri.port, :use_ssl => uri.scheme == 'https') do |http|
http.request(request)
#data = response
end
You can convert JSON response to hash with:
hash_response = JSON.parse(response)
After that you can easily use hash in ruby functions.
The JSON gem is smart and makes it really easy to convert an object to JSON, or convert the JSON string back to an object. This is a simple round-trip example:
require 'json'
foo = {'a' => 1, 'b' => [2, 3]}
json_string = JSON[foo]
json_string # => "{\"a\":1,\"b\":[2,3]}"
bar = JSON[json_string] # => {"a"=>1, "b"=>[2, 3]}
bar == foo # => true
Note that JSON\[...\] senses whether the parameter is a string or a hash (or array). If it's the first it tries to convert the string to a hash or array, or, vice versa. From the documentation:
If object is string-like, parse the string and return the parsed result as a Ruby data structure. Otherwise generate a JSON text from the Ruby data structure object and return it.
You can use the to_json method if you'd like to convert an object also:
foo.to_json # => "{\"a\":1,\"b\":[2,3]}"
There are gotchas you have to be aware of using to_json as it will generate invalid JSON output if you don't give it an array or a hash:
'a'.to_json # => "\"a\""
1.to_json # => "1"
JSON.parse(...) can also be used to turn the string back to an object:
JSON.parse(json_string) # => {"a"=>1, "b"=>[2, 3]}
but I tend to use the shorter JSON[...].
Lets say I have this Hash:
{
:info => [
{
:from => "Ryan Bates",
:message => "sup bra",
:time => "04:35 AM"
}
]
}
I can call the info array by doing hash[:info].
Now when I turn this into JSON (JSON.generate), and then parse it (JSON.parse), I get this hash:
{
"info" => [
{
"from" => "Ryan Bates",
"message" => "sup bra",
"time" => "04:35 AM"
}
]
}
Now if I use hash[:info] it returns nil, but not if I use hash["info"].
Why is this? And is there anyway to fix this incompatibility (besides using string keys from the start)?
The JSON generator converts symbols to strings because JSON does not support symbols. Since JSON keys are all strings, parsing a JSON document will produce a Ruby hash with string keys by default.
You can tell the parser to use symbols instead of strings by using the symbolize_names option.
Example:
original_hash = {:info => [{:from => "Ryan Bates", :message => "sup bra", :time => "04:35 AM"}]}
serialized = JSON.generate(original_hash)
new_hash = JSON.parse(serialized, {:symbolize_names => true})
new_hash[:info]
#=> [{:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}]
Reference: http://www.ruby-doc.org/stdlib-1.9.3/libdoc/json/rdoc/JSON.html#method-i-parse
In short, no. Think about it this way, storing symbols in JSON is the same as storing strings in JSON. So you cannot possibly distinguish between the two when it comes to parsing the JSON string. You can of course convert the string keys back into symbols, or in fact even build a class to interact with JSON which does this automagically, but I would recommend just using strings.
But, just for the sake of it, here are the answers to this question the previous times it's been asked:
what is the best way to convert a json formatted key value pair to ruby hash with symbol as key?
ActiveSupport::JSON decode hash losing symbols
Or perhaps a HashWithIndifferentAccess
I solved my similar issue with calling the with_indifferent_access method on it
Here I have a json string and we can assign it to variable s
s = "{\"foo\":{\"bar\":\"cool\"}}"
So now I can parse the data with the JSON class and assign it to h
h = JSON.parse(s).with_indifferent_access
This will produce a hash that can accept a string or a symbol as the key
h[:foo]["bar"]
#=> "cool"
Use ActiveSupport::JSON.decode, it will allow you to swap json parsers easier
Use ActiveSupport::JSON.decode(my_json, symbolize_names: true)
This will recursively symbolize all keys in the hash.
(confirmed on ruby 2.0)
It's possible to modify all the keys in a hash to convert them from a string to a symbol:
symbol_hash = Hash[obj.map{ |k,v| [k.to_sym, v] }]
puts symbol_hash[:info]
# => {"from"=>"Ryan Bates", "message"=>"sup bra", "time"=>"04:35 AM"}
Unfortunately that doesn't work for the hash nested inside the array. You can, however, write a little recursive method that converts all hash keys:
def symbolize_keys(obj)
#puts obj.class # Useful for debugging
return obj.collect { |a| symbolize_keys(a) } if obj.is_a?(Array)
return obj unless obj.is_a?(Hash)
return Hash[obj.map{ |k,v| [k.to_sym, symbolize_keys(v)] }]
end
symbol_hash = symbolize_keys(hash)
puts symbol_hash[:info]
# => {:from=>"Ryan Bates", :message=>"sup bra", :time=>"04:35 AM"}
You can't use that option like this
ActiveSupport::JSON.decode(str_json, symbolize_names: true)
In Rails 4.1 or later, ActiveSupport::JSON.decode no longer accepts
an options hash for MultiJSON. MultiJSON reached its end of life and
has been removed.
You can use symbolize_keys to handle it.
Warning: It works only for JSON strings parsed to hash.
ActiveSupport::JSON.decode(str_json).symbolize_keys
This question already has answers here:
Parsing a JSON string in Ruby
(8 answers)
Closed 4 years ago.
I'm looking for a simple way to parse JSON, extract a value and write it into a database in Rails.
Specifically what I'm looking for, is a way to extract shortUrl from the JSON returned from the bit.ly API:
{
"errorCode": 0,
"errorMessage": "",
"results":
{
"http://www.foo.com":
{
"hash": "e5TEd",
"shortKeywordUrl": "",
"shortUrl": "http://bit.ly/1a0p8G",
"userHash": "1a0p8G"
}
},
"statusCode": "OK"
}
And then take that shortUrl and write it into an ActiveRecord object associated with the long URL.
This is one of those things that I can think through entirely in concept and when I sit down to execute I realize I've got a lot to learn.
These answers are a bit dated. Therefore I give you:
hash = JSON.parse string
Rails should automagically load the json module for you, so you don't need to add require 'json'.
Parsing JSON in Rails is quite straightforward:
parsed_json = ActiveSupport::JSON.decode(your_json_string)
Let's suppose, the object you want to associate the shortUrl with is a Site object, which has two attributes - short_url and long_url. Than, to get the shortUrl and associate it with the appropriate Site object, you can do something like:
parsed_json["results"].each do |longUrl, convertedUrl|
site = Site.find_by_long_url(longUrl)
site.short_url = convertedUrl["shortUrl"]
site.save
end
This answer is quite old. pguardiario's got it.
One site to check out is JSON implementation for Ruby. This site offers a gem you can install for a much faster C extension variant.
With the benchmarks given their documentation page they claim that it is 21.500x faster than ActiveSupport::JSON.decode
The code would be the same as Milan Novota's answer with this gem, but the parsing would just be:
parsed_json = JSON(your_json_string)
Here is an update for 2013.
Ruby
Ruby 1.9 has a default JSON gem with C extensions. You can use it with
require 'json'
JSON.parse ''{ "x": "y" }'
# => {"x"=>"y"}
The parse! variant can be used for safe sources. There are also other gems, which may be faster than the default implementation. Please refer to multi_json for the list.
Rails
Modern versions of Rails use multi_json, a gem that automatically uses the fastest JSON gem available. Thus, the recommended way is to use
object = ActiveSupport::JSON.decode json_string
Please refer to ActiveSupport::JSON for more information. In particular, the important line in the method source is
data = MultiJson.load(json, options)
Then in your Gemfile, include the gems you want to use. For example,
group :production do
gem 'oj'
end
This can be done as below, just need to use JSON.parse, then you can traverse through it normally with indices.
#ideally not really needed, but in case if JSON.parse is not identifiable in your module
require 'json'
#Assuming data from bitly api is stored in json_data here
json_data = '{
"errorCode": 0,
"errorMessage": "",
"results":
{
"http://www.foo.com":
{
"hash": "e5TEd",
"shortKeywordUrl": "",
"shortUrl": "http://whateverurl",
"userHash": "1a0p8G"
}
},
"statusCode": "OK"
}'
final_data = JSON.parse(json_data)
puts final_data["results"]["http://www.foo.com"]["shortUrl"]
Ruby's bundled JSON is capable of exhibiting a bit of magic on its own.
If you have a string containing JSON serialized data that you want to parse:
JSON[string_to_parse]
JSON will look at the parameter, see it's a String and try decoding it.
Similarly, if you have a hash or array you want serialized, use:
JSON[array_of_values]
Or:
JSON[hash_of_values]
And JSON will serialize it. You can also use the to_json method if you want to avoid the visual similarity of the [] method.
Here are some examples:
hash_of_values = {'foo' => 1, 'bar' => 2}
array_of_values = [hash_of_values]
JSON[hash_of_values]
# => "{\"foo\":1,\"bar\":2}"
JSON[array_of_values]
# => "[{\"foo\":1,\"bar\":2}]"
string_to_parse = array_of_values.to_json
JSON[string_to_parse]
# => [{"foo"=>1, "bar"=>2}]
If you root around in JSON you might notice it's a subset of YAML, and, actually the YAML parser is what's handling JSON. You can do this too:
require 'yaml'
YAML.load(string_to_parse)
# => [{"foo"=>1, "bar"=>2}]
If your app is parsing both YAML and JSON, you can let YAML handle both flavors of serialized data.
require 'json'
out=JSON.parse(input)
This will return a Hash
require 'json'
hash = JSON.parse string
work with the hash and do what you want to do.
The Oj gem (https://github.com/ohler55/oj) should work. It's simple and fast.
http://www.ohler.com/oj/#Simple_JSON_Writing_and_Parsing_Example
require 'oj'
h = { 'one' => 1, 'array' => [ true, false ] }
json = Oj.dump(h)
# json =
# {
# "one":1,
# "array":[
# true,
# false
# ]
# }
h2 = Oj.load(json)
puts "Same? #{h == h2}"
# true
The Oj gem won't work for JRuby. For JRuby this (https://github.com/ralfstx/minimal-json) or this (https://github.com/clojure/data.json) may be good options.
RUBY is case sensitive.
require 'json' # json must be lower case
JSON.parse(<json object>)
for example
JSON.parse(response.body) # JSON must be all upper-case
Here's what I would do:
json = "{\"errorCode\":0,\"errorMessage\":\"\",\"results\":{\"http://www.foo.com\":{\"hash\":\"e5TEd\",\"shortKeywordUrl\":\"\",\"shortUrl\":\"http://b.i.t.ly/1a0p8G\",\"userHash\":\"1a0p8G\"}},\"statusCode\":\"OK\"}"
hash = JSON.parse(json)
results = hash[:results]
If you know the source url then you can use:
source_url = "http://www.foo.com".to_sym
results.fetch(source_url)[:shortUrl]
=> "http://b.i.t.ly/1a0p8G"
If you don't know the key for the source url you can do the following:
results.fetch(results.keys[0])[:shortUrl]
=> "http://b.i.t.ly/1a0p8G"
If you're not wanting to lookup keys using symbols, you can convert the keys in the hash to strings:
results = json[:results].stringify_keys
results.fetch(results.keys[0])["shortUrl"]
=> "http://b.i.t.ly/1a0p8G"
If you're concerned the JSON structure might change you could build a simple JSON Schema and validate the JSON before attempting to access keys. This would provide a guard.
NOTE: Had to mangle the bit.ly url because of posting rules.
You can try something like this:
def details_to_json
{
:id => self.id,
:credit_period_type => self.credit_period_type,
:credit_payment_period => self.credit_payment_period,
}.to_json
end