15

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?

GTDev
  • 5,488
  • 9
  • 49
  • 84

3 Answers3

16

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});
Community
  • 1
  • 1
remigio
  • 4,101
  • 1
  • 26
  • 28
  • 1
    So I'm still a little confused. How do I find the id from the parent object (User) and the child object (UserMission) and pass them to the resource in a rails app with Angularjs and complete a nested relation query? – GTDev Feb 25 '13 at 21:20
  • 2
    By declaring your service default parameters `{user_id: "@user_id", id: "@id"}` you're saying that, when calling service with no parameters, they get values from the object you pass in the call. In your case you're calling the service with no parameters, as in `UserMission.query()`, but you're not passing any value, so the service is called with null values, hence the server gets `/users/user_missions` which gives the error. You should include parameters values in the call, as I indicated in my answer. – remigio Feb 26 '13 at 07:58
10

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.

bpedman
  • 193
  • 2
  • 10
  • Thanks for this explanation of transformResponse! Just what i was looking for. – Casey Jul 11 '13 at 16:59
  • 1
    If you want to get `num_results`, `total_pages` etc in your controller you can just use `query: { method: 'GET', isArray: false }` in your resource and then use `MyModel.query({/*params*/}, function(data) { $scope.numResults = data.num_results; $scope.things = data.objects; });` – Scotty.NET Aug 28 '13 at 08:57
3

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?

holographic-principle
  • 19,688
  • 10
  • 46
  • 62