Accessing data from httparty response - ruby-on-rails

Using httparty I can get the following response:
puts Representative.find_by_zip(46544).inspect
-->
{"results"=>[{"name"=>"Joe Donnelly", "district"=>"2", "office"=>"1218 Longworth", "phone"=>"(202) 225-3915", "link"=>"http://donnelly.house.gov/", "state"=>"IN"}]
source of the example: http://railstips.org/blog/archives/2008/07/29/it-s-an-httparty-and-everyone-is-invited/
but I fail to access the data, for example:
Representative.find_by_zip(46544).inspect["name"] returns nil
How can I access individual elements of this response?

Object#inspect returns a string, not a hash. You want this:
Representative.find_by_zip(46544)['results'][0]['name']
This is what's going on: Representative#find_by_zip returns a Hash with just one index: 'results'. The item at 'results' is an array, which in this case only contains one element, so we use [0] to get the first (and only) element. That element is itself a hash that has the 'name' key, which points to the name of the first (and only) representative returned.
When you have complex hashes and arrays it's sometimes useful to format it in a more readable way to figure out how to get at the data you want:
{ "results" => [
{ "name" => "Joe Donnelly",
"district" => "2",
"office => "1218 Longworth",
"phone" => "(202) 225-3915",
"link" => "http://donnelly.house.gov/",
"state" => "IN"
}
]
}
That should make it more clear what's inside what here.

To Access the individual elements, You can use:-
If the response is JSON:-
You can use:-
response.parsed_response["key"]
If your response is a string then, you can use:-
data = JSON.parse(resp.body)
The response type depends, on the content type you are setting while requesting the data:-
'Content-Type' => 'application/json'
If you don't set the content type it returns response as string.

Related

Need alternative for eval

I have a string
string = '{"a" => [{"b" => 2}]}'
eval(string)
# => {"a" => [{"b" => 2}]}
I need alternative for this to have output like {"a" => [{"b" => 2}]}
When storing data in strings that will be parsed programmatically, it's best to format those strings using a standardized data-interchange format, such as JSON. Your string, formatted into JSON, would look like this:
{"a": [{"b": 2}]}
If you have any control over how the data is saved in excel, you should make sure it's saved in JSON format like this. If, for some reason, you're not allowed to modify the format of the data in excel, your next best option is to convert it to JSON before parsing it.
Fortunately for you, the data is already very similar to JSON. The only difference is that JSON uses : instead of =>, so you can do this:
require "json"
string = '{"a" => [{"b" => 2}]}'.gsub("=>", ":")
data = JSON.parse string
p data # => {"a" => [{"b" => 2}]}

How do I iterate over this JSON object?

This is an object that is returned as a response in an HTTP POST request:
res.body
=> "{\"id\":\"a3adasfaf3\",\"url\":\"https://someurl/a3adasfaf3\",\"created\":\"2016-05-30T07:00:58Z\",\"modified\":\"2016-05-30T07:00:58Z\",\"files_hash\":\"cljhlk2j3l2kj34hlke18\",\"language\":\"ruby\",\"title\":\"Some weird hello world message\",\"public\":false,\"owner\":\"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k\",\"files\":[{\"name\":\"Some-weird-hello-world-message.rb\",\"content\":\"puts \\\"Some weird hello world message.\\\"\\r\\n\"}]}"
I am trying to pull out, and translate the various attributes of that response. For instance, at the very least the id and url.
How do I do this?
For the record, I am using Ruby's NET/HTTP std lib to send the POST request and get back this response.
Edit 1
For bonus points, all I want is the actual value stored in each attribute (i.e. the actual id (which is just a string) and a url (which is a typical URL). So if you included how I might both access that attribute and then sanitize it at the same time that would be awesome.
Use JSON.parse to parse the response.
response = "{\"id\":\"a3adasfaf3\",\"url\":\"https://someurl/a3adasfaf3\",\"created\":\"2016-05-30T07:00:58Z\",\"modified\":\"2016-05-30T07:00:58Z\",\"files_hash\":\"cljhlk2j3l2kj34hlke18\",\"language\":\"ruby\",\"title\":\"Some weird hello world message\",\"public\":false,\"owner\":\"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k\",\"files\":[{\"name\":\"Some-weird-hello-world-message.rb\",\"content\":\"puts \\\"Some weird hello world message.\\\"\\r\\n\"}]}"
require 'json'
JSON.parse response
# output:
# {"id"=>"a3adasfaf3", "url"=>"https://someurl/a3adasfaf3", "created"=>"2016-05-30T07:00:58Z", "modified"=>"2016-05-30T07:00:58Z", "files_hash"=>"cljhlk2j3l2kj34hlke18", "language"=>"ruby", "title"=>"Some weird hello world message", "public"=>false, "owner"=>"kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k", "files"=>[{"name"=>"Some-weird-hello-world-message.rb", "content"=>"puts \"Some weird hello world message.\"\r\n"}]}
response["name"] # => a3adasfaf3
You need to parse it with JSON.parse
Example:
parsed_hash = JSON.parse res.body
Result:
{
"id" => "a3adasfaf3",
"url" => "https://someurl/a3adasfaf3",
"created" => "2016-05-30T07:00:58Z",
"modified" => "2016-05-30T07:00:58Z",
"files_hash" => "cljhlk2j3l2kj34hlke18",
"language" => "ruby",
"title" => "Some weird hello world message",
"public" => false,
"owner" => "kljhlk2jh34lk2jh4l2kj3h4l2kj4h23l4kjh2l4k",
"files" => [
[0] {
"name" => "Some-weird-hello-world-message.rb",
"content" => "puts \"Some weird hello world message.\"\r\n"
}
]
}
To access the id:
parsed_hash['id']
To access the url:
parsed_hash['url']
Want to access it by symbols ?
parsed_hash = JSON.parse(res.body).symbolize_keys
You can now access id and url by parsed_hash[:id] and parsed_hash[:url]

Convert sent params to json

I have controller method which perform some actions for POST sent json params, but the problem is when I try to send json params without json header.
I would like to handle this exception by converting string to json and here the problems begins.
Let's say that I have simple JSON like this:
{"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
I have placed binding.pry at the begining of method and I try to get params from there. I figured out that request.body will return me object #<StringIO:0x007fbdb5cf9fe8> which I have to convert to JSON.
First thing I have tried was:
[1] pry(#<TestController>)> request.body.to_json
=> "[\"{\\\"menu\\\": {\\n\",\" \\\"id\\\": \\\"file\\\",\\n\",\" \\\"value\\\": \\\"File\\\",\\n\",\" \\\"popup\\\": {\\n\",\" \\\"menuitem\\\": [\\n\",\" {\\\"value\\\": \\\"New\\\", \\\"onclick\\\": \\\"CreateNewDoc()\\\"},\\n\",\" {\\\"value\\\": \\\"Open\\\", \\\"onclick\\\": \\\"OpenDoc()\\\"},\\n\",\" {\\\"value\\\": \\\"Close\\\", \\\"onclick\\\": \\\"CloseDoc()\\\"}\\n\",\" ]\\n\",\" }\\n\",\"}}\"]"
but it is not result I was looking for.
I have tried several more converts, like:
[2] pry(#<TestsController>)> ActiveSupport::JSON.decode(request.body.to_json)
=> []
Which also gives me nothing. I'm out of ideas.
I would like to achive something like this:
[1] pry(#<TestsController>)> params
=> {"menu"=>{"id"=>"file", "value"=>"File", "popup"=>{"menuitem"=>[{"value"=>"New", "onclick"=>"CreateNewDoc()"}, {"value"=>"Open", "onclick"=>"OpenDoc()"}, {"value"=>"Close", "onclick"=>"CloseDoc()"}]}},
"controller"=>"payments",
"action"=>"notification",
"payment"=>{"menu"=>{"id"=>"file", "value"=>"File", "popup"=>{"menuitem"=>[{"value"=>"New", "onclick"=>"CreateNewDoc()"}, {"value"=>"Open", "onclick"=>"OpenDoc()"}, {"value"=>"Close", "onclick"=>"CloseDoc()"}]}}}}
This is scenario for sending params with json header. In that can I can easily iterate through them.
You should use JSON.parse on request.body.read
request.body.rewind
JSON.parse(request.body.read)
Have you tried
request.body replaced with env['rack.input'].read
json = JSON.parse env['rack.input'].read
OR
json = JSON.parse request.body.read
as stated here
Since you are using RoR, if you are using Action Controller Parameters you can use the to_hash method and then use to_json (which is only on RoR, not part of Ruby) to convert your permitted params, like this:
params.permit(:attributes).to_hash.to_json
In my case this worked:
JSON.parse(params[:attributes].to_json)

issue with passing array of hashes as parameter to POST in rails application with typhoeus

I have two rails services. One serving the UI and some basic functionality (UIService) and another which manages the underlying models and database interactions (MainService).
At the UIService, I have a form that collects a list of items and uses that to POST to MainService via jQuery.
I take the javascript array and call the jQuery.post to UIService first, like this -
var selected_items = new Array();
// Filled up via the form...
params={"name":$("#name_input").val(),
"items": selected_items };
jQuery.post("/items", params);
This is then converted to an array of hashes with the key "item_id" and then forwarded to the MainService via Typhoeus like this -
items = []
item = {}
params[:items].each do |i|
item[:item_id] = i
end
## Gives me this ---> items = [ {item_id: 189}, {item_id: 187} ]
req = Typhoeus::Request.new("#{my_url}/items/",
method: :POST,
headers: {"Accepts" => "application/json"})
hydra = Typhoeus::Hydra.new
hydra.queue(req)
hydra.run
At the MainService, I need the JSON schema to be in a particular format. Basically an array of items... like this -
{ "name": "test_items", "items": [ {"item_id":"189"},{"item_id": "187"} ] }
The issue is that when I collect the array from jQuery and pass it to UIService, it looks like this in the params -
[ {item_id: 189}, {item_id: 187} ]
But, when it arrives at MainService, it becomes this -
{"name"=>"test_items",
"items"=>{"0"=>{"item_id"=>"189"}, "1"=>{"item_id"=>"187"}}
So, I need the array of items to be key'ed with "item_id" and inserted into the params. I tried several ways to keep it as an array of hashes, but it always ends up in the wrong format at the destination.
I tried various workarounds, like stringifying, not stringifying, building my own array of hashes etc. I'm pretty stuck at this point. Any ideas? Anything I'm doing wrong or not doing?
I can make it work other JSON schemas, but I need to stick to this one.
The issue was with the way I was passing the parameters into typhoeus
before (with issue) --
req = Typhoeus::Request.new("#{Rails.application.config.custom_ads_url}/groups",
method: :POST,
params: parameters,
headers: {"Content-Type" => "application/json", "AUTHORIZATION" => "auth_token #{user.auth_token}"})
after (works) --
notice that I needed to convert to json and put it in the body. 'params' in typhoeus was being considered as a custom hash.
req = Typhoeus::Request.new("#{Rails.application.config.custom_ads_url}/groups",
method: :POST,
body: parameters.to_json,
headers: {"Content-Type" => "application/json", "AUTHORIZATION" => "auth_token #{user.auth_token}"})
There is also a middleware provided by Typhoeus which does the correct conversion: http://rubydoc.info/github/typhoeus/typhoeus/frames/Rack/Typhoeus/Middleware/ParamsDecoder.
If you're using the Typhoeus class method .post you can implement your request like so:
Typhoeus.post(
"#{Rails.application.config.custom_ads_url}/groups",
headers: { 'Content-Type'=> "application/json" },
body: parameters.to_json
)

Ruby on Rails: Passing a hash as a parameter for URL parameters... how do I remove the brackets?

I've made this method here:
def get_api_xml_from_url(url, params = {}, api_key = SharedTest.user_api_key)
response = get(url, params, :format => "xml", :api_key => api_key)
assert_response :success
response_xml_hash = CobraVsMongoose.xml_to_hash(response.body)
return response_xml_hash, response
end
but, the issue is that the params are goofing up the GET() call. I'm guessing because the url doesn't want get(url, {param, praam param}, format, etc)
but rather, it wants, get(url, param, param, param, format, etc)
How do I remove the brackets from the params variable? such that when no params are sent, nothing breaks. =\
so :format and :api_key are the default params you want to pass to the get call in any case, right?
You can merge your defaults with whatever gets passed to your get_api_xml_from_url method in the first place.
get(url, params.merge(:format => "xml", :api_key => api_key)
UPDATE:
A little more explanation on whats happening here. get takes two arguments, the url and a hash. Being able to write the hash without curly brackets is just syntactic sugar in ruby. Under the hood, it realizes that your last params are all key/value pairs and it passes them all as just one hash to the function.
What you've done was passing 3 Arguments to get. The url, your params hash (enclosed in curly brackets and therefor recognized as an argument itself) and finally the remaining key/value pairs.

Resources