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.
0
12 Answers
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'
.
0
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
2
Newer version of Rails uses ‘multi-json’ gem, which uses the fastest json decoder installed in the Gemfile (e.g. oj). Therefore calling ActiveSupport::JSON will be fast if you have installed faster JSON parsers. (edit rejected therefore post as comment)
– lulalalaAs for this comment
multi-json
is actually being dumped. There are benchmarks out there that showmulti-json
is actually slower than the built injson
gem and other implementation of json parsers out there.
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)
1
Taken from the documentation, the parsing is now: parsed_json = JSON.parse(your_json_string)
– user1026130
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
2
parse json, not generate it!
– retoSorry about that, I was to quick on the trigger, lol. Use the Oj gem. – ohler.com/oj/#Simple_JSON_Writing_and_Parsing_Example