331

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 12

482

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'.

Sign up to request clarification or add additional context in comments.

Comments

191

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 Comments

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)
As for this comment multi-json is actually being dumped. There are benchmarks out there that show multi-json is actually slower than the built in json gem and other implementation of json parsers out there.
55

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 Comment

Taken from the documentation, the parsing is now: parsed_json = JSON.parse(your_json_string)
25

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

Comments

11

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"]

Comments

8

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.

Comments

7
require 'json'
out=JSON.parse(input)

This will return a Hash

Comments

6
require 'json'

hash = JSON.parse string

work with the hash and do what you want to do.

Comments

2

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.

Comments

2

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

Comments

2

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.

Comments

-3

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 Comments

parse json, not generate it!
Sorry about that, I was to quick on the trigger, lol. Use the Oj gem. - ohler.com/oj/#Simple_JSON_Writing_and_Parsing_Example

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.