Difficulty accessing entire hash in ruby with data pulled from api - ruby

I'm currently trying to pull data via the Yelp API, and can only seem to access half of the hash.
This code:
client = Yelp::Client.new
include Yelp::V2::Search::Request
request = Location.new(
:city => 'Melbourne',
:limit => 1) response = client.search(request)
puts response
Will output the full hash of
{"region"=>{"span"=>{"latitude_delta"=>0.0, "longitude_delta"=>0.0},
"center"=>{"latitude"=>28.0772451, "longitude"=>-80.6045478}},
"total"=>2324, "businesses"=>[{"is_claimed"=>false, "rating"=>4.5,
"mobile_url"=>"http://m.yelp.com/biz/el-ambia-cubano-melbourne",
"rating_img_url"=>"http://s3-media2.fl.yelpassets.com/assets/2/www/img/99493c12711e/ico/stars/v1/stars_4_half.png",
"review_count"=>168, "name"=>"El Ambia Cubano",
"snippet_image_url"=>"http://s3-media1.fl.yelpassets.com/photo/NgfGcZGdYlhTO18p8Shqrw/ms.jpg",
"rating_img_url_small"=>"http://s3-media2.fl.yelpassets.com/assets/2/www/img/a5221e66bc70/ico/stars/v1/stars_small_4_half.png",
"url"=>"http://www.yelp.com/biz/el-ambia-cubano-melbourne",
"phone"=>"3213278389", "snippet_text"=>"4.5 stars to me - rounded up
because the kids liked it too.\n\nWent here for lunch based mostly on
yelp reviews. Rest of my crew voted against Indian or Thai....",
"image_url"=>"http://s3-media3.fl.yelpassets.com/bphoto/pnZSlPiBDl1bS9w7saOAZA/ms.jpg",
"categories"=>[["Cuban", "cuban"]],
"display_phone"=>"+1-321-327-8389",
"rating_img_url_large"=>"http://s3-media4.fl.yelpassets.com/assets/2/www/img/9f83790ff7f6/ico/stars/v1/stars_large_4_half.png",
"id"=>"el-ambia-cubano-melbourne", "is_closed"=>false,
"location"=>{"city"=>"Melbourne", "display_address"=>["950 E Melbourne
Ave", "Melbourne, FL 32901"], "geo_accuracy"=>8.0,
"postal_code"=>"32901", "country_code"=>"US", "address"=>["950 E
Melbourne Ave"], "coordinate"=>{"latitude"=>28.0771809,
"longitude"=>-80.6044922}, "state_code"=>"FL"}}]}
I can access the region info by using
puts response["region"]
But I can't seem to access the rest of the hash? I'm specifically trying to extract the business name. What am I missing and need to do to access the entire hash?

businesses seems to be an array. Something like
response["businesses"][0]["name"]
Will retrive the name of the first business

Related

Retrieving user metadata about a provisioned SoftLayer server comes back null

I'm trying to retrieve the user meta information for each machine consistently but what I'm finding is most of my machines are missing this data. I'd like to understand better what is required for this user data to be there. I'm curious if a server can be requested and provisioned without requiring user information (e.g. an API call to order a server and no user data is given). Or whether I am missing something in how I retrieve this information. Here is the basic ruby program I'm running:
user = ###
api_key = ###
client = SoftLayer::Client.new(:username => user, :api_key => api_key, :timeout => 999999)
list_of_virtual_machines = client['Account'].result_limit(i*50,50).object_mask("mask[id, billingItem[recurringFee, associatedChildren[recurringFee], orderItem[description, order[userRecord[username], id]]], userData]").getVirtualGuests
for x in 0..list_of_virtual_machines.length - 1
pp list_of_virtual_machines[i]['userData']
if list_of_virtual_machines[i]['billingItem'] && list_of_virtual_machines[i]['billingItem']['orderItem'] && list_of_virtual_machines[i]['billingItem']['orderItem']['order'] && list_of_virtual_machines[i]['billingItem']['orderItem']['order']['userRecord']
pp list_of_virtual_machines[i]['billingItem']['orderItem']['order']['userRecord']
end
end
My prints are consistently showing null. This question is related to a similar question I asked not too long ago (but the focus of that question moved towards the provisionDate):
How to get order username and provisionDate for all SoftLayer machines using Ruby?
They are missing that data because you did not added.
you can create the user data at moment to order a new server or VSI, you just have to send the data in your order request either using the createObject method or the placeOrder method. see http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest/createObject
e.g.
{
"userData": [
{
"value": "someValue"
}
]
}
or you can set it after the server has been provisioned using these methods
http://sldn.softlayer.com/reference/services/SoftLayer_Virtual_Guest/setUserMetadata
http://sldn.softlayer.com/reference/services/SoftLayer_Hardware_Server/setUserMetadata
Basically the usermetadata are useful if you are going to use a post install script. The usermetadata value is not required to order a new server
take a look this article for examples:
http://sldn.softlayer.com/blog/jarteche/getting-started-user-data-and-post-provisioning-scripts

How to get the full street address via the geocoder gem?

I am using geocoder with Google to validate addresses and give me back the correct values if they are munged slightly as well as to acquire latitude and longitude. I think I may be a bit off in my implementation here because it just feels so clunky and also I'm finding that some of the addresses are missing the street number.
I am starting off with the following code:
result = Geocoder.search(full_address_to_verify)
if result != []
street_address = result[0].address_components[1]["long_name"]
city = result[0].address_components[2]["long_name"]
state = result[0].address_components[5]["long_name"]
zip = result[0].address_components[7]["long_name"]
end
I have found that sometimes I get multiple results, and so I am going with the first one ([0] above). Further, I have found some queerness in that most of the time result[0].address_components[1] contains the full address, including the street_number, but once in a while it does not and I have to then add result[0].address_components[0]. I have yet to figure out a rhyme or reason to this.
Ultimately my goal here is to retrieve the USA street number + street, city, state and zip code fields into separate variables.
So my question is, is there a better way to retrieve the address so that the street number is always associated properly with the route?
From the documentation I'm not really seeing any clean methods that would just simply give me the desired address fields without pulling the data out of the individual fields from the request reply...
A couple of years late to the party. Extracting an address from the google geocoding API is straightforward and rather cumbersome with the nested address_components.
Luckily, the geocoder gem has built-in methods to access the address info. Read more on the docs.
Right, the address_components should enable you to do what you want to accomplish. For the rhyme, you can refer to this part of the documentation about address type.
Google Maps API marked which kind of the component this field belong by putting a string in this location:
result[0].address_components[i].types[0]
You should get your correspond values based on the types, but not the position of the address_components.
This is how Google approached it in their Places Autocomplete API demo:
var componentForm = {
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
country: 'long_name',
postal_code: 'short_name'
};
...
...
// Get each component of the address from the place details
// and fill the corresponding field on the form.
for (var i = 0; i < place.address_components.length; i++) {
var addressType = place.address_components[i].types[0];
if (componentForm[addressType]) {
var val = place.address_components[i][componentForm[addressType]];
document.getElementById(addressType).value = val;
}
}

Return database results in the same JSON parent and children

I have Team and Players classes and want to return the data in one JSON string which contains Team info but at the same time it displays all the information about the players.
class Team < ActiveRecord::Base
has_many :players
end
class Players < ActiveRecord::Base
belongs_to :team
end
I know how to retrieve the information about team and players but not in the same query. Another problem is I don't how to merge the result JSONs in one JSON.
team = Team.last.to_json
player = team.players.to_json
How can I query the info about Team and Players in the same query. I tried:
#team = Team.includes(:players).where(players: {team_id: Team.last}).last.to_json
and it only returns me information about the team. I want a JSON like:
-id
-name
-players
-player
-player
In case it's impossible, how can I merge into one JSON all the information from the two queries.
You can write a "join" to incorporate the players in the team with the team information. At that point you'll have a structure that has the information needed to create the JSON. See "12 Joining Tables" from the Active Record documentation for more information.
Or, you can make two separate queries, then create a bit more complex JSON hash or array allowing you to output both sets of data into one larger serialized object. For instance:
require 'json'
team = {
'name' => 'bears'
}
players = {
'1' => 'fred',
'2' => 'joe'
}
puts ({
'team' => team,
'players' => players
}).to_json
Here's the output:
{"team":{"name":"bears"},"players":{"1":"fred","2":"joe"}}
Here's the data returned back to the Ruby object:
data = '{"team":{"name":"bears"},"players":{"1":"fred","2":"joe"}}'
JSON[data]
# => {"team"=>{"name"=>"bears"}, "players"=>{"1"=>"fred", "2"=>"joe"}}
Also, since you're using Sinatra, it's not necessary to use Active Record. Sequel is a very good ORM, and is my personal favorite when working with Sinatra. You might find it easier to work with.
Another option to manual serialization is to use ActiveModel::Serializer which allows you to define relationships between objects and gives you finer grained choices of what to include when you serialize, what to filter out and what related objects to preload. An alternative could also be Rabl which also has quite a nice API.
If you're just playing around with a small amount of JSON this might be overkill, but it's a nice practice to be more organized

How to use Sequel to select one field from database

I am using Sinatra and Sequel with PostgreSQL.
After authentication, I want to welcome the user by printing their name but I cannot get only the value of the user's name from the database, it comes out as a hash.
The query is:
current_user = DB[:users].select(:username).where('password = ?', password).first
and the resulting piece of data is:
Welcome, {:username=>"Rich"}
which looks rather weird, I would prefer it to read "Welcome, Rich".
What am I doing wrong here? I tried the same query without 'first" at the end and that does not work either.
You can either pull the (single) column you selected out of the Hash you are given:
current_user = DB[:users].select(:username).where('password=?', password).first[:username]
Or you can map your results to an array of usernames and pull the first:
# Using a hash in the filter method is simpler than SQL placeholders.
current_user = DB[:users].filter(password:password).select_map(:username).first
But the best way is to get only the user you care about, and then get the name:
# Using [] on a dataset returns the first row matching the criteria
current_user = DB[:users][password:password][:username]
Try Sequel::Dataset#get. Also, as Phrogz points out, Sequel::Dataset#where can take a hash (it will securely escape values to prevent injection attacks).
current_username = DB[:users].where(password: password).get(:username)
There's also Sequel::Dataset#where_single_value, which is optimized for this exact situation:
current_username = DB[:users].select(:username).where_single_value(password: password)

Facebook Graph API only returning 50 comments

I'm using the koala gem as show in Railscasts episode #361. I'm attempting to get all of the comments of a given Post but Facebook only seems to be giving me back the last 50 comments on the post. Is this a limitation of Facebook's Graph API or am I doing something wrong?
fb = Koala::Facebook::API.new oauth_token
post = fb.get_object(id_of_the_post)
comments = fb.get_object(post['id'])['comments']['data']
puts comments.size # prints 50
Graph API paginates the result when is a larger number of posts than the limit that is set (in your case 50).
In order to access the next page of results, call "next_page" method:
comments = fb.get_object(post['id'])
while comments['comments']['data'].present?
# Make operations with your results
comments = comments.next_page
end
Also, by looking in source one can see that "get_object" method receives 3 parameters:
def get_object(id, args = {}, options = {})
This way, you can raise your posts per page to as many posts as you want:
comments = fb.get_object(post['id'], {:limit => 1000})

Resources