Guide to working with Roar collections and paginating results. This library uses some metaprogramming to create collections and paginate results. While this may reduce the amount of code you need to write, it can obfuscate the implementation and make it difficult to debug. Therefore, I would suggest using this as a guide for how to work with Roar to create your own implementation. I hope it helps!
Add this line to your application's Gemfile:
gem 'roar-contrib'
And then execute:
$ bundle
Or install it yourself as:
$ gem install roar-contrib
When using Decorators, include Roar::Contrib::Decorator::CollectionRepresenter
to create a Representer for a collection of resources.
class SongRepresenter < Roar::Decorator
include Roar::JSON
property :name
end
class SongsRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Contrib::Decorator::CollectionRepresenter
end
This will create a collection (songs
in this case) based on the name of the Representer, using the singular representer (SongRepresenter) to serialize each individual resource in the collection. Therefore, a GET request to /songs
would give you:
{
"songs": [
{
"name": "Thriller"
},
{
"name": "One More Time"
},
{
"name": "Good Vibrations"
}
]
}
If you need more custom behavior and want to define your own collection, you can do it like so:
class SongsRepresenter < Roar::Decorator
include Roar::JSON
collection :top_songs,
:exec_context => :decorator,
:decorator => TopSong
def top_songs
represented
end
end
Roar-contrib pagination works with either will_paginate or Kaminari. It is based on Nick Sutterer's blog post. You must install one of these for roar-contrib pagination to work. In your Gemfile, include either
gem 'will_paginate'
or
gem 'kaminari'
To paginate, include Roar::Contrib::Decorator::PageRepresenter
and define page_url
in the paginated Representer like so:
class SongRepresenter < Roar::Decorator
include Roar::JSON
property :name
end
class SongsRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Contrib::Decorator::PageRepresenter
collection :songs,
:exec_context => :decorator,
:decorator => SongRepresenter
def songs
represented
end
# If using roar-rails, url helpers are also available here
def page_url(args)
"http://www.roar-contrib.com/songs?#{args.to_query}"
end
end
As you may have guessed, you can combine the CollectionRepresenter
and PageRepresenter
to DRY up the example above. Woot Woot! 😝 💥
class SongRepresenter < Roar::Decorator
include Roar::JSON
property :name
end
class SongsRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Contrib::Decorator::PageRepresenter
include Roar::Contrib::Decorator::CollectionRepresenter
def page_url(args)
"http://www.roar-contrib.com/songs?#{args.to_query}"
end
end
If you are using Rails, your controller(s) may look like the following...
# Using will_paginate
class SongsController < ActionController::Base
include Roar::Rails::ControllerAdditions
represents :json, Song
def index
@songs = Song.paginate :page => params[:page], :per_page => params[:per_page]
respond_with @songs
end
end
# Using Kaminari
class SongsController < ActionController::Base
include Roar::Rails::ControllerAdditions
represents :json, Song
def index
@songs = Song.page(params[:page]).per params[:per_page]
respond_with @songs
end
end
Now, a GET request to /songs?page=3&per_page=1
would give you:
{
"total_entries": 3,
"links": [
{
"rel": "self",
"href": "http://www.roar-contrib.com/songs?page=3&per_page=1"
},
{
"rel": "previous",
"href": "http://www.roar-contrib.com/songs?page=2&per_page=1"
}
],
"songs": [
{
"name": "Good Vibrations"
}
]
}
You can define additional pagination properties in your response such as per_page
provided by will_paginate, or limit_value
provided by Kaminari, by defining the property in your paginated representer.
class SongsRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Contrib::Decorator::PageRepresenter
include Roar::Contrib::Decorator::CollectionRepresenter
property :per_page # Only works with will_paginate
def page_url(args)
songs_url args
end
end
Roar-contrib provides you with the following methods defined on the Decorator instance that work with either will_paginate
or Kaminari
:
#current_page
#next_page
#previous_page
#per_page
#total_entries
You can use them as properties by telling Roar to execute the methods in the context of the Decorator.
class SongsRepresenter < Roar::Decorator
include Roar::JSON
include Roar::Contrib::Decorator::PageRepresenter
include Roar::Contrib::Decorator::CollectionRepresenter
property :per_page, :exec_context => :decorator # Works with either will_paginate or Kaminari
def page_url(args)
songs_url args
end
end
Contributions welcome!! 😄
- Fork it ( https://github.com/sweatshirtio/roar-contrib/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request