Transforming JSON to nested ruby hash - ruby-on-rails

I have a JSON block that I want to convert to a ruby hash.
json_blob = {"WHATEVER"=>{"FOO"=>"BAR", "CAT"=>"DAY}}
so that when I am using the data, I can check whether the data is there. Example:
hashed_json_blob[:whatever][:foo] returns "bar"
and also, I could handle values that don't exist either (they were omitted in the json_blob).
hashed_json_blob[:whatever][:nonexistant] returns nil
Note: if there is an easier way with the data as XML, that can work to. The json_blob was pulled using JSON.parse

your json_blob object is already a hash (minus one missing quote at the end of "DAY"):
json_blob = {"WHATEVER"=>{"FOO"=>"BAR", "CAT"=>"DAY"}}
with this you can do:
json_blob["WHATEVER"]
=> {"FOO"=>"BAR", "CAT"=>"DAY"}
json_blob["WHATEVER"]["FOO"]
=> "BAR"
The same data as a json object would look like this:
{"WHATEVER":{"FOO":"BAR","CAT":"DAY"}}

gem install json
require 'json'
json_blob = {"WHATEVER"=>{"FOO"=>"BAR", "CAT"=>"DAY}}
abc = JSON.parse(json_blob)
now you can perform operations on abc

Related

How to rename a symbol in hash parameters?

I have parameters from an external API that formats JSON responses using CamelCase that I want to fit into my Rails app:
{"AccountID"=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
"ChannelProductDescription"=>"0004", "Currency"=>"CAD",
"CurrentBalance"=> {"Amount"=>"162563.64", "Currency"=>"CAD"}}
Using the below script I converted them to lower case:
data = JSON.parse(response, symbolize_keys: true)
data = {:_json => data} unless data.is_a?(Hash)
data.deep_transform_keys!(&:underscore)
data.deep_symbolize_keys!
Leaving me correctly formatted params like this:
{:account_id=>"REAWLLY_LONG_HASH_API_KEY_FROM_EXTERNAL_SERVICE",
:channel_product_description=>"SAVINGS", :currency=>"CAD",
:current_balance=> {:amount=>"43.00", :currency=>"CAD"}}
I'm trying to map this external API response into a generic Rails model Account, where JSON from this API call will return cleanly as parameters into my database to allow a clean saving interface such as:
#account = Account.create(ParamParser.call(params))
But I ran into a problem with converting :account_id, as that param conflicts with the primary key of my database.
To get around this, my idea is to convert all symbol instances of params[:account_id] into params[:account_key_id], so that those params don't conflict with my databases existing account_id field.
How do I do this, and is there a better approach for consuming external JSON API's than what I've described here?
Hash#deep_transform_keys does this:
Returns a new hash with all keys converted by the block operation.
This includes the keys from the root hash and from all
nested hashes and arrays.
So you could do it in one pass with an appropriate block, something like:
data.deep_transform_keys! do |key|
key = key.underscore.to_sym
key = :account_key_id if(key == :account_id)
key
end
You might as well drop the symbolize_keys: true flag to JSON.parse too, you're changing all the keys anyway so don't bother.
If you're doing this sort of thing a lot then you could write a method that takes a key mapping Hash and gives you a lambda for transforming the keys:
def key_mangler(key_map = { })
->(key) do
key = key.underscore.to_sym
key = key_map[key] if(key_map.has_key?(key))
key
end
end
and then say things like:
data.deep_transform_keys!(&key_mangler(:account_id => :account_key_id))
You might want to use a different name than key_mangler of course but that name is good enough to illustrate the idea.
BTW, if you're sending this JSON into the database then you probably don't need to bother with symbol keys, JSON only uses strings for keys so you'll be converting strings to symbols only for them to be converted back to strings. Of course, if you're symbolizing the keys when pulling the JSON out of the database then you'll probably want to be consistent and use symbols across the board.
In addition to the previous answer...
Unfortunately, there is, to my knowledge, no method on Hash that does this in one operation. I've always accomplished this by brute force, as in:
hash[:new_key] = hash[:old_key]
hash.delete(:old_key)
A shortcut for this, suggested in the comment below by "mu is too short", is:
hash[:new_key] = hash.delete(:old_key)
To illustrate in irb:
2.4.1 :002 > h = { foo: :bar }
=> {:foo=>:bar}
2.4.1 :003 > h[:foo_new] = h.delete(:foo)
=> :bar
2.4.1 :004 > h
=> {:foo_new=>:bar}

Ruby : How to parse a jsonp and save json data to database

I want to parse the JSONP data and save that data into my data base .
I have my jsonp url lets say this >>http://a0.awsstatic.com/pricing/1/ec2/pricing-data-transfer-with-regions.min.js?callback=callback&_=1409722308446
Its not normal json object so how can i parse this json in ruby/ruby on rails and save the data into my database. I want to save the data in table having filed lets say region , name ,type, price .
What are the ways to do the same.
JSONP is a work around for the same origin policy in client side JavaScript. It isn't required for processing data in Ruby. Firstly I would try to find the data available in plain JSON, without the callback.
If, however, that URL is absolutely the only one you can call for this data, then I would strip away the callback using a regular expression and then parse the plain JSON data.
If you have already loaded the contents of that file into a variable called jsonp, then something like this might work:
require 'net/http'
require 'json'
uri = URI.parse('http://a0.awsstatic.com/pricing/1/ec2/rhel-od.min.js?callback=callback&_=1409731896563')
jsonp = Net::HTTP.get(uri)
jsonp.gsub!(/^.*callback\(/, '') # removes the comment and callback function from the start of the string
jsonp.gsub!(/\);$/, '') # removes the end of the callback function
jsonp.gsub!(/(\w+):/, '"\1":')
hash = JSON.parse(jsonp)
then hash will have the parsed JSON from the response.
Please note, this code has no error handling and should be treated as a starting point for your final solution.
[edit] Added the third gsub to change the JavaScript style keys to JSON style keys. This works in this case because the keys all appear to be simple enough to fit that regex.
[edit2] Added way to load the JSONP with Net::HTTP
If what you're really trying to do is parse the Amazon price list JS file into Ruby, there is a better (read: safer--no evals) way to do it:
require 'net/http'
require 'json'
JSON.parse(
Net::HTTP.get(
URI.parse('http://a0.awsstatic.com/pricing/1/ec2/rhel-od.min.js')
).split('callback(')[1].sub(');', '').gsub(/(\w+):/, '"\1":')
)
As the data is as a raw JS object form, it's actually valid Ruby:
require 'json'
data = '{key: "value", key2: 33}'
obj = eval data
obj[:key]
#=> "value"
obj.to_json
# => "{\"key\":\"value\",\"key2\":33}"
You must trust your source completely though - this would allow the running of abstract Ruby code if the data were tampered with - which could in turn run abstract command-line terminal code, using the back-tick operators. This could delete your hard drive for example.

JSON to Ruby on Rails Create Action

I am using an API for movies, for the most part I use a gem, but in order to get certain information, I have to use RestClient.get methods.
response = RestClient.get "http://api.themoviedb.org/3/movie/8699/keywords", headers
puts response
If I run this code, it returns this JSON "extract"
{"id":8699,"keywords":[{"id":917,"name":"journalism"},{"id":4411,"name":"sexism"},{"id":6198,"name":"ladder"},{"id":8531,"name":"panda"},{"id":18290,"name":"1970s"},{"id":18298,"name":"tv show in film"},{"id":41390,"name":"mustache"},{"id":165288,"name":"misogynist"},{"id":167241,"name":"newsroom"},{"id":167250,"name":"teleprompter"},{"id":167252,"name":"what happened to epilogue"},{"id":167254,"name":"gang warfare"},{"id":167256,"name":"multiple cameos"},{"id":179430,"name":"aftercreditsstinger"},{"id":179431,"name":"duringcreditsstinger"},{"id":185281,"name":"news spoof"}]}
Now what I need to do is be able to do is turn the above into a rails readable piece of code, so that I can then put it into a database.
More specifically, I would like to take the above information and be able to execute it as such
keywords.each do |keyword|
Keyword.create(name: keyword.name, tmdbid: keyword.id)
end
So that it creates a new Keyword based on each keyword and its name & id based on the JSON File
You can use JSON.parse to turn it into a hash
keywords = JSON.parse(response)["keywords"]
It will be faster if you create all keywords at once by first create correct array of values to be saved. Here is what I will do
keywords = JSON.parse(response)["keywords"].map do |k|
{ name: k["name"], tmdbid: k["id"] }
end
Keyword.create(keywords) #one SQL statement only
Regards

Ruby getting deeply nested JSON API data

I have a rails app which gets a response from World Weather Online API. I'm using the rest-client gem and the response is in JSON format.
I parse the response using:
parsed_response = JSON.parse(response)
Where parsed_response is obviously a hash.
The data I need are strings inside a hash inside an array inside a hash inside another array inside another hash inside another hash.
The inner-most nested hashes are inside ["hourly"], an array of 8 hashes, each with 20 keys, possessing string values of various weather parameters. Each of these hashes in the array is a different time of day (the forecast is three-hourly, 3*8 = 24hours).
So, for example, if I want the swell height in metres at 9pm, I find it with the following call:
#swell_height = parsed_data["data"]["weather"][0]["hourly"][7]["swellHeight_m"]
Where the 7th element in the array correspond to "time" => "2100"
While I can definitely work with this, I'm curious as to whether there is a more straightforward method of accessing my data, like if it was a database table, I could use active record, something like:
#swell_height = parsed_data.swellHeight_m.where(:time => "2100")
You may want to look at JSONPath. It does exactly what you need. Its syntax is very similar to XPath, but JSONPath works with JSON data (as obvious).
There is a Ruby implementation: https://github.com/joshbuddy/jsonpath
I personally use it in every project where I need to test JSON responses.

jRuby hash iteration newbie here

I am very new to rails in general and what I have is a hash being passed as json for one format and now I need to pass it to the view to work with but I have no idea how to iterate over the hash to make it work in the view as I need to do some type of each loop over it. Its a 2 dimensional hash dunno if that means anything or not.
edit
example
{"status":"successful","service_list":[{"service_name":"mySQL","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"PHP","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"APache","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"Jetty","status":"RUNNING","status_message":"No errors reported","host":"1"}]}
This renders fine when I do it as JSON, but using the same thing to render it out in an HTML based view is where I am getting stuck
You have converted a Ruby has to a JSON hash, which is a Javascript format. In Ruby you would access a hash as follows:
hash = {"foo": "bar"}
puts hash["foo"] # This returns "bar"
JSON is similar to Ruby, and can be accessed in the same manner:
var hash = {"foo": "bar"};
alert(hash["foo"]); # This alerts "bar"
If you want to iterate through this collection in Javascript, you can use a for loop:
var data = {"status":"successful","service_list":[{"service_name":"mySQL","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"PHP","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"APache","status":"RUNNING","status_message":"No errors reported","host":"1"},{"service_name":"Jetty","status":"RUNNING","status_message":"No errors reported","host":"1"}]};
for(x=0;x<data["service_list"].length;x++) {
alert(data["service_list"][x]["service_name"]); # This returns "mySQL", ...
};
If you are wanting to convert this JSON object to a Ruby has you can call "JSON.parse" with your JSON string as an argument.

Resources