How to parse api request using ruby - ruby-on-rails

I am learning how to use Yelp API from this yelp blog and yelp github on Rails. I was able to connect to Yelp service and got a response back, but I don't know what to do with the response that I got back.
Here is what I did, on Rails Console:
2.2.2 :057 > response = client.search('los angeles', {limit: 2})
=> #<Yelp::Response::Search:0x007fff32edc2c0 #region=#<Yelp::Response::Model::Region:0x007fff35ddf6d0 #span=#<Yelp::Response::Model::RegionSpan:0x007fff35ddf450 #latitude_delta=0.04455494999999132, #longitude_delta=0.02209966000000918>, #center=#<Yelp::Response::Model::RegionCenter:0x007fff35ddf5e0 #latitude=34.08390635, #longitude=-118.3184503>>,...
What kind of format is that? this article says that when I make API call to Yelp, it gives ruby object, but I am not sure what data type #<Yelp::Response... is. I guess I was expecting a ruby array/ json format return, like stated in the article:
`
search
response = client.search('San Francisco')
response.businesses
[< Business 1>, < Business 2 >, ...]
response.businesses[0].name
"Kim Makoi, DC"
response.businesses[0].rating
5.0
If I want to select a specific information, say display_address, or neighborhood from the return API, how can I do that? (Here is the end part of the same API request):
...#display_address=["6353 Yucca St", "Hollywood", "Los Angeles, CA 90028"], #geo_accuracy=8.0, #postal_code="90028", #country_code="US", #address=["6353 Yucca St"], #coordinate=#<Yelp::Response::Model::Coordinate:0x007fff35ddf7e8 #latitude=34.10413, #longitude=-118.32834>, #state_code="CA", #neighborhoods=["Hollywood"]>, #deals=nil, #gift_certificates=nil, #reviews=nil>]>

1.
If you were to call the API directly (say, from cURL), you'd get JSON back.
You're using the Yelp gem, though, so it's helpfully converting that JSON into a ruby object for you. If you're interested in the construction of the object, you can take a look at how the gem is doing the conversion on GitHub.
You should be able to interact with that response just like the article states, i.e. results.businesses should give you an array of businesses found.
More concretely, it looks like you can do something like:
results.businesses[0].display_address to get the display address for the first business found
results.businesses[0].neighborhoods is an array of all neighborhoods associated with that same business.

Related

EmberJS 2.7, Rails 5, AMS 0.10.2 - GET resources collection where fieldX=[B or C]

I have an EmberJS filter like this:
/app/routes/trails/new.js
model: function (filterCurrentEmployees) {
return Ember.RSVP.hash({
trail: this.store.createRecord('trail'),
employees: this.store.query('employee', { status: '1,2'}).then(
function(data) {return data})
})
},
I was hoping that status: '1,2' would end up as a normal Rails param so I could do params[:status] and then filter the returned employees (you know so the db would get a query like 'where status IN ['1','2']')
But when this filter query is sent to Rails API I get this error:
ActiveModelSerializers::Adapter::JsonApi::Deserialization::InvalidDocument (Invalid payload ({:data=>"Expected hash"}): {"status"=>"1,2", "controller"=>"employees", "action"=>"index"}):
which occurs here in the controller:
api/app/controllers/employees.rb
def employee_params
ActiveModelSerializers::Deserialization.jsonapi_parse!(params)
end
but that is needed for AMS to work with Ember.
So I presume something is wrong with the way I am sending/creating the query in EmberJS?
It seems to be trying to make a GET collection request. Not sure really and this explains sort-of what is going on at the Rails end, but I don't know how to get Ember to create the filter properly so that AMS is happy to accept it.
EDIT - JSON-API Spec Reference
I was under the impression that AMS and Ember 2.7 with JSON-API 'just work out of the box'. I was actually expecting the Ember filter to comply with the spec and send
/employees?filter=status[1,2]
but it seems to not be doing that. AMS says the same thing here.
UPDATE
So with some pointers from the comments (thank you) I learned that the structure of the query hash might be incorrect. I also tried changing 'query' to filter but that then raises an actual Ember error:
The filter API has been moved to a plugin. To enable store.filter using an environment flag, or to use an alternative, you can visit the ember-data-filter addon page.
Now I don't know what the difference is between an Ember query and an Ember filter, perhaps a filter only runs on the client? Who knows, the docs are so sparse and so many questions on this are 1 or 2 years old.
So after much digging around for Ember Gold Nuggets, I found out that Controllers are STILL needed for...you guessed it...Query Parameters.
I've never used a Controller, and thought I never needed one.
So it seems I was basing my attempt at using query parameters on outdated information and code examples.
For those who run into this, the gold nuggets are here and here.
Also, it seems Javascript Object parameters as per JSON-API spec are not yet supported in Ember, according to this, although it's nearly a year old so do not know if that is still true.
UPDATE
So, after further gold mining, it seems I was confused and that Controllers are needed for Query Parameters in Ember on the client side, to assist the frontend application when it transitions from one route to another (and that is when you need a Controller to set them up).
But I want to just send a query parameter from within the Route code directly to the API, and examples of doing that are very hard to find.
So in the Rails Log I would expect to see BEFORE deserialization by ASM:
Rails.logger.info "Params are: #{params.to_json}"
something like this:
Params are:
{"data":{"filter":{"status["1,2"]}},
"controller":"employees","action":"index"}
ASM expects 'data' to be the root element of the hash, and then inside that I can place my filter. For example, from the Ember Route:
model: function () {
let myFilter = {};
myFilter.data = { filter: {status: ['1,2']}};
return Ember.RSVP.hash({
trail: this.store.createRecord('trail'),
employees: this.store.query('employee', myFilter).then(function(data) {return data})
})
},

Rails TMDB API Browse to Find

TMDB.org recently made a change to their API which removes the capability to browse their database.
My Rails app used to use the tmdb-ruby gem to browse the TMDB database, but this gem only worked with v2.0 of the API, which is now defunct.
TMDB.org recommends using this gem, and since it is forked from the gem I previously used, it makes it a bit easier.
My PostgreSQL database is already populated with data imported from TMDB when v2.0 was still extant and when I could use the browse feature.
How can I now use the find feature (ie: #movie = TmdbMovie.find(:title => "Iron Man", :limit => 1) ) to find a random movie, without supplying the title of the Movie.
This is my rake file which worked with the older gem.
I would like to know how to have it work the same way but whilst using the find instead of the browse.
Thanks
I don't think find is what you need in order to get what you want (getting the oldest movies in the database and working its way up to the newest movie). Looking at the TMDb API documentation, it looks like they now have discover that may have replaced the browse that you used to use.
I don't see discover anywhere in Irio's ruby-tmdb fork, but it looks like most of the specific methods they have (like TmdbMovie.find) call a generic method Tmdb.api_call.
You should be able to use the generic method to do something like:
api_return = Tmdb.api_call(
"discover/movie",
{
page: 1,
sort_by: 'release_date.asc',
query: '' # Necessary because Tmdb.api_call throws a nil error if you don't specify a query param value
},
"en"
)
results = api_return["results"]
results.flatten!(1)
results.uniq!
results.delete_if &:nil?
results.map!{|m| TmdbMovie.new(m, true)} # `true` tells TmdbMovie.new to expand results
If this works, you could even fork Irio's fork, implement a TmdbMovie.discover method supporting all the options and handling edge cases like TmdbMovie.find does, and send them a pull request since it just looks like they haven't gotten around to implementing this yet and I'm sure other people would like to have this method as well :)

Magento SalesOrderList... is there a ligth weight version of this, or a way to trim down the returned value

I am attempting to get all the orders from a magento instance. Once a day we grab all the orders.. (sometimes a few thousand)
Extra stuff that's more why I ask:
I'm using ruby-on-rails to grab the orders. This involves sending the soap call to the magento instance. It's easy as.
Once I have the response, I convert it into a Hash (a tree) and then pick out the increment id's of the orders and proceed to call getOrder with the increment id.
I have two problems with what's going on now, one operational, and one religious.
Grabbing the XML response to the list request takes really really long and when you tack on the work involved in converting the XML to a hash, I'm seeing a really slow processes.
The religious bit is that I just want the increment_ids so why do I have to pay for the processing/bandwidth to support a hugely bloated response.
Ok so the question...
Is there a way to set the response returned from Magento, to include only specific fields? Only the updated_at and the increment_id for instance.
If not, is there another call I'm not aware of, that can get just the increment_ids and date?
Edit
Below is an example of what I'm looking for from magento but it's for ebay. I send this xml up to ebay, and get back a really really specific bit of info about the product. It works for orders and such too. I can say "only this" and get just that. I want the same from Magento
<GetItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<SKU>b123-332</SKU><OutputSelector>ItemId</OutputSelector>
</GetItemRequest>
I've created a rubygem that gives you your salesOrderList response in the form of a hash, and you can do what you want with the orders after you've received them back (i.e. select the fields you want including increment_id). Just run
gem install magento_api_wrapper
To do what you want to do, you would do something like this:
api = MagentoApiWrapper::Sales.new(magento_url: "yourmagentostore.com/index.php", magento_username: "soap_api_username", magento_api_key: "userkey123")
orders = api.order_list(simple_filters: [{key: "status" value: "complete"}])
orders.map {|o| [o.increment_id, o.items.first.sku] }
Rough guess, but you get the idea. You would get the array of hashes back and you can do what you want with them after that. Good luck!

Ruby on Rails 3 and Google Book Search

I'm trying to get started using the Google Data API for Google Book Search in my Ruby on Rails 3 application, and I don't even understand how to get started. What gems do I need? What do I need to do in order to do something simple like searching for books with a title of Foobar?
Following up on the deprecation issue: I've just published GoogleBooks, a Ruby wrapper that enables users to query for books precisely in the manner described.
It's updated to hook into the present-day Google API, so it's not affected by the recent deprecation of the Google Book Search API.
If you're looking to use Google Books to retrieve information about books, you can use their data API: http://code.google.com/apis/books/docs/gdata/developers_guide_protocol.html
Making requests to a URL like http://books.google.com/books/feeds/volumes?q=isbn:9780974514055 will return XML with the book's information. You could use the Nokogiri gem to parse the result ( http://nokogiri.org/ ).
One thing to be aware of is that, to get the full descriptions for books, you need to get the entry instead of just the feed results.
Here's a short example of how you could get a book's information from Google:
require 'open-uri'
require 'nokogiri'
class Book
attr_accessor :title, :description
def self.from_google(title)
book = self.new
entry = Nokogiri::XML(open "http://books.google.com/books/feeds/volumes?q=#{title}").css("entry id").first
xml = Nokogiri::XML(open entry.text) if entry
return book unless xml
book.title = xml.css("entry dc|title").first.text unless xml.css("entry dc|title").empty?
book.description = xml.css("entry dc|description").first.text unless xml.css("entry dc|description").empty?
book
end
end
b = Book.from_google("Ruby")
p b
if you want to use the api, i think you will have to use jruby and their java api. no ruby api exists for the book search, according to this: http://code.google.com/apis/books/docs/gdata/code.html
for connecting with google, try using the gdata gem.
http://code.google.com/apis/gdata/articles/gdata_on_rails.html#SetupRails

Accessing object values that have reserved keywords as names in Rails

I'm accessing the Amazon AWS API using the ruby-aaws gem, but without going to much into details of the API or the gem, I think my problem is more of a general nature.
When I query the API I will end up with "object array", let's call it item, containing the API response.
I can easily access the data in the array, e.g. puts item.item_attributes.artist.to_s
Now the API returns attributes whose identifier are reserved words in Rails, e.g. format or binding.
So doing this:
puts item.item_attributes.format.to_s will return method not found
while
puts item.item_attributes.binding.to_s will return some object hash like #<Binding:0xb70478e4>.
I can see that there are values under that name when doing
puts item.item_attributes.to_yaml
Snippet from the resulting yaml show artist and binding:
--- !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::ItemAttributes
__val__:
artist: !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::Artist
__val__: Summerbirds in the Cellar
binding: !seq:Amazon::AWS::AWSArray
- !ruby/object:Amazon::AWS::AWSObject::Binding
__val__: Vinyl
This was probably a very detailed explanation with a very simple solution, but I can't seem to find the solution.
edit
Finally found it. I guess it is because it is an array of objects, duh...
puts item.item_attributes[0].binding.to_s
You may be able to access the individual attributes by using [] instead of the method name (which is probably provided using method_missing anyway).
So, item.item_attributes[:artist].to_s may return what you want. If it doesn't it would be worth trying 'artist' as the key instead.
Finally found it. I guess it is because it is an array of objects, duh...
puts item.item_attributes[0].binding.to_s

Resources