Search code examples
ruby-on-railsrabl

Returning 2 collections in RABL?


I'm trying to return 2 collections in RABL. But I'm having some trouble. What happens is it only returns the second collection when I run it.

Here is the function for the index page the rabl is rendering:

def index
   @friends = @currentuser.friends
   @pendingfriends = @currentuser.pending_friends
end

In my RABL page I am trying to return both collections like so:

collection @friends, :root => "friends", :object_root => "user"
attributes :id, :username

collection @pendingfriends, :root => "pendingfriends", :object_root => "user"
attributes :id, :username

What happens is it only renders the second collection "pending friends":

{
    "pendingfriends": [
        {
            "user": {
                "id": 3,
                "username": "ken"
            }
        }
    ]
}

If I delete the second collection though the first one appears fine. I'm wondering whats the correct way I can render the 2 collections in my RABL template.

Thanks for any help.


Solution

  • Based on your code looks like you want user as the document root. Then create two child nodes, one for each collection. basically 'gluing' the collections to the user. Since they are basically the same Model, you'll need to alias the collections by using nodes for each collection. Using partials to keep it DRY.

     @user = @currentuser # for example below
    

    file : users/user.rabl

     object @user
     extends "users/base"
    
     node :friends do |u|
      partial("users/friends", :object => u.friends) # :object => @friends)
     end
    
     node :pendingfriends do |u|
      partial("users/friends", :object => u.pending_friends) # @pendingfriends)
     end
    

    file : users/base.rabl

     attributes :id, :name
    

    file : users/friends.rabl

    collection @nil , :object_root => false
    extends "users/base"
    

    The one thing I dont link about this is the collection object @nil (used to express a point) is ignored since in user.rabl the object is explicitly set. Which works for this case, but prevents calling friends.rabl directly. So if you wish to also call this file directly, set to a global collection you intend to use... like @users. Then you can call collection.rabl directly in your controller if you wish and not just as a partial. Then...

    file : users/friends.rabl

    collection @users , :object_root => false
    extends "users/base"
    

    this would give you a structure of

     {
         "user": {
             "id": "hello",
             "name": "me",
             "friends": [
                 {
                     "id": "hello",
                     "name": "me2"
                 }
             ],
             "pendingfriends": [
                 {
                     "id": "hello",
                     "name": "me3"
                 }
             ]
         }
     }
    

    This gives further benefit as now you can build a collection for users ( and their friends ) as such

    file : users/users.rabl

     collection @users , :object_root => false
     extends 'users/user'