How do I parse JSON with Ruby on Rails? [duplicate]
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
精彩评论