Skip to content

Instantly share code, notes, and snippets.

@openfirmware
Created April 1, 2014 18:40
Show Gist options
  • Select an option

  • Save openfirmware/9920310 to your computer and use it in GitHub Desktop.

Select an option

Save openfirmware/9920310 to your computer and use it in GitHub Desktop.
roar-rails nested association pagination example

Roar-rails and representing AssocationRelations with Pagination

The roar-rails gem can be used to generate custom REST representations of resources for your Rails application. If you have an app with any sort of nested resources, then you may not have many found examples of representing the layers of resources. Here is one that I've found works and is mostly straight forward.

As the routes file and models show, it is just a simple has_many/belongs_to relationship. You likely want to show representations of the resources: People, Person, Pets for Person, and Pet. Writing representers for People, Person, and Pet are simple enough, and the roar-rails documentation explains it. There are multiple ways to represent the Pets for a Person; which is a resource in its own right. Because it is a resource, it should have its own representation: PersonPetsRepresenter.

A simple way is to respond_with @person and then read the #pets relation in the representer. But if you want to do pagination (will_paginate) in the controller, you have to respond_with @pets. As @pets is an AssociationRelation, the typical methods don't work the same. We can however access both ends of the relation with #all and #proxy_association.owner. The represented object will also respond to will_paginate methods. This can be seen in the PersonPetsRepresenter example.

For more information on pagination with roar-rails, check out Nick Sutterer's article.

class Person < ActiveRecord::Base
has_many :pets, inverse_of: :person
end
class PersonPetsRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
property :total_entries
collection :pets, class: Pet, extend: PetRepresenter,
embedded: true, decorator_scope: true
def pets
represented.all
end
def person
represented.proxy_association.owner
end
link :self do
person_pets_path(person, page: represented.current_page)
end
link :person do
person_path(person)
end
link :previous do
person_pets_path(person, page: represented.previous_page) if represented.previous_page
end
link :next do
person_pets_path(person, page: represented.next_page) if represented.next_page
end
end
class Pet < ActiveRecord::Base
belongs_to :person, inverse_of: pets
end
class PetRepresenter < Roar::Decorator
include Roar::Representer::JSON::HAL
property :id
link :self do
person_pet_path(represented.person, represented)
end
link :person do
person_path(represented.person)
end
end
class PetsController < ApplicationController
include Roar::Rails::ControllerAdditions
respond_to :json, :hal, :html
def index
@person = People.where(id: params[:person_id]).take!
@pets = @person.pets.paginate(page: params[:page])
respond_with @pets, represent_with: PersonPetsRepresenter
end
def show
@person = People.where(id: params[:person_id]).take!
@pet = @person.pets.where(id: params[:id]).take!
respond_with @pet, represent_with: PetRepresenter
end
end
Application.routes.draw do
resources :people do
resources :pets
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment