Angular JS ngResource with nested resources - ruby-on-rails-3

I'm trying out angular JS and I want to get data from a nested resource defined in my rails application.
I wrote the following lines:
UserMission = $resource("/users/:user_id/user_missions/:id", {user_id: "#user_id", id: "#id"}, {update: {method: "PUT"}})
$scope.user_missions = UserMission.query()
and I get the following error:
Processing by UsersController#show as JSON
Parameters: {"id"=>"user_missions"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", "user_missions"]]
Completed 404 Not Found in 10ms
ActiveRecord::RecordNotFound (Couldn't find User with id=user_missions):
app/controllers/users_controller.rb:100:in `current_resource'
app/controllers/application_controller.rb:34:in `authorize'
My rails routes are organized like so:
resources :users do
resources :user_missions
end
I think it comes down to me not understanding "#id". It says it comes off of the "data object" from the angularjs site and I am not exactly sure what that means.
Any help would be appreciated thanks.
Update
Another question. I have not found any examples of rails with angularjs using nested resources (an example User has_many :missions, through: :user_missions ) with $resource. Is there a good example of angularjs manipulating nested resources (with $resource) with ajax?

Read through my answer to your previous question, you should include the values for both the parameters in an object you pass as a parameter in the call, i. e.:
$scope.user_missions = UserMission.query({user_id: some_value, id: some_other_value});

I was also looking for a way to handle nested resources with ngResource. I am not familiar with how rails works or what your data looks like but this is what I had:
{"num_results": 5, "objects": [....], "page": 1, "total_pages": 1}
I needed to reach in and grab the nested objects array for the query action. Using the 1.0 version of angular this is not possible. However, with the 1.1 version (I tested with 1.1.3) it is possible to do this.
In my controller I just setup the resource like this:
$scope.MyModel = $resource("/api/mymodel/:id",
{},
{'query': {method: 'GET', isArray: true, "transformResponse": function (data) {
return JSON.parse(data).objects;
}}});
The key here is the transformResponse function passed as part of the action config. In 1.1 any extra config items in the action config are passed down into the $http config for the request. The $http service allows a transformResponse function that can manipulate the data returned by the request. Using this function I can reach into the nested structure and return the array I need for the action.
One caveat to notice here is that the transformResponse function receives a string value, so you must first parse the data into what you are expecting. The other caveat is that you return the actual final data value you want, NOT a string. Even though you receive a string value you should return the end data value required.

The "data object" refers to your instance objects ($scope.user_missions is an array of those objects -- or would be rather, if you actually managed to successfully retrieve it), and you can think of UserMission as being the class.
If you call the query method on the class object (UserMission), in your case, it requires at least one parameter in order to know which User's UserMission(s) to retrieve.
UserMission.query({user_id: <USER_ID>});
The above would perform a "GET ALL"
To obtain a specific UserMission ( "GET ONE" ), you would have to supply both IDs
UserMission.query({user_id: <USER_ID>, id: <MISSION_ID>});
Makes sense?

Related

Instagram API error

I using Instagram API to get user info
api = InstagramAPI(access_token=access_token)
profile = api.user(user_id="kallaucyahoocojp") # I try to put output data to profile variable here
And I get the below error:
DownloadError: Unable to fetch URL: https://api.instagram.com/v1/users/kallaucyahoocojp.json?access_token=(u'1191812153.f78cd79.d2d99595c79d4c23a7994d85ea0d412c', {u'username': u'kallaucyahoocojp', u'bio': u'\u30c4\u30a4\u30c3\u30bf\u30d5\u30a9\u30ed\u30ef\u30fc\u5897\u52a0\u30b5\u30fc\u30d3\u30b9', u'website': u'http://twitter\u30d5\u30a9\u30ed\u30ef\u30fc.jp', u'profile_picture': u'http://images.ak.instagram.com/profiles/anonymousUser.jpg', u'full_name': u'Kallauc', u'id': u'1191812153'})
Can anybody help me to fix it?
You need to pass the numeric-based user id, rather than the username. For example, instead of passing kallaucyahoocojp, you might pass 1234 if t
Here's how to get the ID if you don't have it:
Search for the instagram user id using this endpoint. In the python api:
api.user_search(q="kallaucyahoocojp", count=100)
Check the results for an exact string match on each user name while iterating through the results (calling .lower() to be sure to ignore potential case issues).
If you don't find the user in the first page of results, call to the next page using the max id returned.
Get the user id object from the returned from the matching users search result, then call your original function again with the numeric id.
A couple of very important notes:
Notice that I called the search function for users with a count of 100. You can pick any number, but contrary to other SO posts, the first user is not always the user you want in a search. The search can and will match partials, and not always according to an exact match first. How do I know? I have production instagram apps. I will qualify and say that usually the results are in the first 2-3 matches. Decide what is cheaper; repeated API calls that bring you closer to the limit, or 1 large bulk call where you are certain to get all the results.
The python Instagram API last I checked does a terrible job returning paging information. You actually get the paging URL which defeats the purpose of the python API itself to get additional pages. Your options are extract the next id parameter from the URL using urlparse or something similar, or fix the API to return the paging data as an object per the json (I've done both). What happens is the API itself is discarding part of the json and only giving you the URL which normally you don't want/need.
In your example, here's the search response:
{
"meta": {
"code": 200
},
"data": [
{
"username": "kallaucyahoocojp",
"bio": "ツイッタフォロワー増加サービス",
"website": "http://twitterフォロワー.jp",
"profile_picture": "http://images.ak.instagram.com/profiles/anonymousUser.jpg",
"full_name": "Kallauc",
"id": "1191812153"
}
]
}
Revising your call:
api = InstagramAPI(access_token=access_token)
profile = api.user(user_id="1191812153")
I should note that you may not need to call the user call if you did a search because you may simply have all the info you need. It will depend on what you are doing of course, so I am giving you the general method to use the rest of the user api.
For extracting profile info using Instagram API, userid is required.
The endpoint for extracting userID:
https://api.instagram.com/v1/users/search?q=[username]&access_token=[HERE]
The endpoint for extracting profile info:
https://api.instagram.com/v1/users/[userid]/?access_token=[HERE]
Note that before extracting information, check the login permissions for your access token.

Is this RESTfull?

I'm a little confused as to what the collection URI's should return.
Say I have a collection, /users of decently large elements. Then we have the expected:
GET /users/123 // returns user element with identifier 123
But what should
GET /users
return? If the collection is large, and the elements are large, it's probably not a good thing to return all elements. Perhaps instead, GET requests at the /users level should return element summaries (identifiers and possibly a few properties), while GET requests at the /users/ level should return actual elements. Then you could do something like;
GET /users
> [{name: abc, id: 1}, {name: def, id: 2}, {name: ghi, id: 3}, ...]
GET /users/2
> {name: def, prop1: *, prop2: *, ...}
Which could be a good way to lazily load data if you wanted to preview important application-domain properties before requesting them in their entirety. With this, in order to apply queries, you'd do something like
GET /users?prop1=value // returns element summaries of elements with prop1=value
GET /users/?prop1=value // returns elements with prop1 = value
Is this approach OK? Or do the other methods acting on /users then loose meaning.. (ex. PUT /users ?)
I personally like the style where /users does not return all users but returns information needed to then query specific users. So the summaries approach is how I would generally write it.
If you were filtering or querying, I would go with the first one you provided:
GET /users?prop1=value
I don't care for the second one
GET /users/?prop1=value
because it can be easily misunderstood or lead to confusing and unintended bugs (missing one slash still works but completely changes the results).
You might want to go with an approach of an alternative URL for returning specific users based on search parameters such as
GET /users?prop1=value // returns element summaries based on results of prop1 matching
GET /users/find?prop1=value // returns elements with prop1 = value
Obviously your wording could change (find/search) or you could use a completely different URI but I try to avoid things where two different meanings are a single character/symbol apart to avoid unintended mistakes. Another option would be to make sure you outline this clearly in provided documentation so anyone consuming your API is alerted about this potential.
Actually expanding on this I would go with the all construct.
So instead of using find/search I would provide:
GET /users // returns summaries
GET /users/# // returns element
GET /users/all // returns all elements
GET /users/all?prop1=value // returns all elements that match the filter

How do you load collections that live on a rails' action besides index?

Batmanjs sample project Classifieds used to do this by passing a :url option to override the default resource name, but this has now been deprecated.
Classifieds.Ad.load {url: "/ads/search.json?q=#{params.q}"}, (error, records) =>
throw error if error
#set 'searchAds', records
I have seen most people pass query params to the index action and handle logic depending on the filters passed. Is there a working example somewhere of how to load a collection from a rails action other than index?

Ruby on Rails: Basic parameterized queries and URL formation

I'm trying to learn how to query a rails database and return the results as JSON. In my example, I want to query the data using the parameters, city and state.
So far, in my controller, I have gotten the following action to work.
def state
#bathrooms = Bathroom.where("state = ?" ,params[:state])
respond_to do |format|
format.json { render :json => #bathrooms }
format.js { render :nothing => true }
end
end
This is also my routing entry.
match '/bathrooms/state/:state',
:controller => "bathrooms",
:action => "state"
I can call this resource with the following URL:
http://localhost:3000/bathrooms/state/CA.json
That's all good but I don't know how to query by more than one parameter. Adding and AND clause in the controller seems to be easy enough.
BUT....I don't know how to
a.) Correctly write the routing entry?
b.) What would the URL look like if I tested it in a browser?
I've tried to understand rake routes but I must be missing something.
Could someone provide a basic example for what the action should look like? What the routing entry should look like and what does the URL to access the resource look like?
Again, if written in SQL, this is what I would like to be returned.
SELECT * from bathrooms WHERE city='Chicago' AND state = 'IL'
Any help appreciated.
You don't have to pass everything by the route - the URL also support GET parameters - those are the parameters you usually see after the question mark in the URL. You can add those GET parameters without changing your routes: http://localhost:3000/bathrooms/state/IL.json?city=Chicago. Then your can access the city parameter via params[:city]. but in your case, I think it will be better to use http://localhost:3000/bathrooms/index.json?state=IL&city=Chicago. You'll also need to change your routing to
match '/bathrooms/index',
:controller=>:bathrooms,
:action=>:index
and put the code in the index method of BathroomsController. You access the parameters the same - but the concept is different - you don't enter a state and look for bathrooms by city, you just look for bathrooms by state and city.
Anyways, you don't want to write the URL by hand - you want to a Rails helper or an HTML form generate it:
link_to "bathroom in Chicago, IL",:controller=>:bathrooms,:action=>:index,:state=>'IL',:city=>'Chicago'
If you want to use a form(to let the users choose their own state and city), you need to set it's method to GET:
form_tag {:controller=>:bathrooms,:action=>:index},:method=>:get do
and put state and city as fields.
It's also worth noting that while you can use SQL's AND to perform a search by multiple fields, you can also chain where methods: Bathroom.where(:state=>params[:state]).where(:city=>params[:city]).
You can put any arbitrary parameters in your querystring.
For example:
http://localhost:3000/bathrooms/state/CA.json?city=Chicago
your query looks like this:
#bathrooms = Bathroom.where("state = ? and city= ?" ,params[:state], params[:city])

What is the proper RESTful way to "like" something in Rails 3?

Let's say I have a Rails 3 app that displays videos. The user can "Like" or "Dislike" the videos. Also, they can like/dislike other things like games. I need some help in the overall design and how to handle the RESTful routes.
Currently, I have a Like Class that uses polymorphic design so that objects are "likeable" (likeable_id, likeable_type)
I want to do this via AJAX (jQuery 1.5). So I was thinking something like:
javascript
// these are toggle buttons
$("likeVideo").click( function() {
$.ajax({
url: "/likes/video/" + video_id,
method: "POST",
....
});
} );
$("likeGame").click( function() {
$.ajax({
url: "/likes/game/" + game_id,
method: "POST",
....
});
} );
rails controller
Class Likes < ApplicationController
def video
# so that if you liked it before, you now DON'T LIKE it so change to -1
# or if you DIDN'T like it before, you now LIKE IT so change to 1
# do a "find_or_create_by..." and return JSON
# the JSON returned will notify JS if you now like or dislike so that the
# button can be changed to match
end
def game
# same logic as above
end
end
Routes
match "/likes/video/:id" => "likes#video", :as => :likes_video
match "/likes/game/:id" => "likes#game", :as => :likes_game
Does this logic seem correct? I am doing a POST via AJAX. Technically, shouldn't I be doing a PUT? Or am I being too picky over that?
Also, my controller uses non-standard verbs. Like video and game. Should I worry about that? Sometimes I get confused on how to match up the "correct" verbs.
An alternative would be to post to something like /likes/:id with a data structure that contains the type (game or video). Then I could wrap that in one verb in the controller...maybe even Update (PUT).
Any suggestions would be appreciated.
Rest architectural style does not specify which "verb" you should be using for what. It simply says that one can use HTTP if they want to for connectors.
What you are looking for is HTTP specifications for method definitions. In particular POST is intended for:
- Annotation of existing resources;
- Posting a message to a bulletin board, newsgroup, mailing list,
or similar group of articles;
- Providing a block of data, such as the result of submitting a
form, to a data-handling process;
- Extending a database through an append operation.
while PUT:
requests that the enclosed entity be stored under the supplied Request-URI. If the Request-URI refers to an already existing resource, the enclosed entity SHOULD be considered as a modified version of the one residing on the origin server.
Which category your functionality falls into is up to you - as long as you are consistent with yourself about it.