Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add pagination properly according to json-api #2

Merged
merged 1 commit into from
Aug 21, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .rspec
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
--format documentation
--color
41 changes: 31 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Requirement

It is based on [will_paginate](https://github.com/mislav/will_paginate).
`JbuilderPagination` relies on a paginated collection with the methods `current_page`, `total_pages`, and `size`, such as are supported by both [Kaminari](https://github.com/amatsuda/kaminari) or [WillPaginate](https://github.com/mislav/will_paginate).

## Installation

Expand All @@ -24,21 +24,42 @@ Or install it yourself as:

## Usage

###### Kaminari examples
```ruby
#array
@posts = Kaminari.paginate_array([1, 2, 3]).page(3).per(1)

#active_record
@posts = Post.page(3).per(1)
```

###### WillPaginate examples

```ruby
#array
@posts = [1,2,3].paginate(page: 3, per_page: 1)

#active_record
@posts = Post.page(3).per_page(1)
```

And then in your `*.json.jbuilder`

```ruby
json.links do
json.pages! @servers, url: "https://api.example.com/v1/servers"
json.pages! @posts, url: "http://example.com/posts", query_parameters: { additional: 'parameters' }
end

# =>
# "links": {
# "pages": {
# "first": "https://api.example.com/v1/servers/v1/servers?page=1&per_page=1",
# "prev": "https://api.example.com/v1/servers/v1/servers?page=1&per_page=1",
# "last": "https://api.example.com/v1/servers/v1/servers?page=3&per_page=1",
# "next": "https://api.example.com/v1/servers/v1/servers?page=3&per_page=1"
# }
# },
# "links": {
# "self": "http://example.com/posts?page[number]=3&page[size]=1&additional=parameters",
# "first": "http://example.com/posts?page[number]=1&page[size]=1&additional=parameters",
# "prev": "http://example.com/posts?page[number]=2&page[size]=1&additional=parameters",
# "next": "http://example.com/posts?page[number]=4&page[size]=1&additional=parameters",
# "last": "http://example.com/posts?page[number]=13&page[size]=1&additional=parameters"
# }
```
The options `url` and `query_parameters` are opcionals.

In case there is no pagination at all, `links` will be omitted.

Expand Down
34 changes: 23 additions & 11 deletions lib/jbuilder/pagination/pages.rb
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
class Jbuilder
ONE_PAGE = 1

def pages!(collection, options={})
return unless collection
return unless collection && is_paginated?(collection)

pages do
pages_from(collection).map do |k, v|
_set_value k, "#{options[:url]}?page=#{v}&per_page=#{collection.per_page}"
end
pages_from(collection).map do |key, value|
params = query_parameters(options).merge(page: { number: value, size: collection.size }).to_query
_set_value key, "#{options.fetch(:url, nil)}?#{params}"
end
end

private

def pages_from(collection)
return {} if collection.total_pages == 1

{}.tap do |pages|
unless collection.current_page == 1
pages[:first] = 1
pages[:prev] = collection.current_page - 1
pages[:self] = collection.current_page
return pages if collection.total_pages == ONE_PAGE

unless collection.current_page == ONE_PAGE
pages[:first] = ONE_PAGE
pages[:prev] = collection.current_page - ONE_PAGE
end

unless collection.current_page == collection.total_pages
pages[:next] = collection.current_page + ONE_PAGE
pages[:last] = collection.total_pages
pages[:next] = collection.current_page + 1
end
end
end

def query_parameters(options)
@query_parameters ||= options.fetch(:query_parameters, {})
end

def is_paginated?(collection)
collection.respond_to?(:current_page) &&
collection.respond_to?(:total_pages) &&
collection.respond_to?(:size)
end
end
2 changes: 1 addition & 1 deletion lib/jbuilder/pagination/version.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module Jbuilder
class Pagination
VERSION = "0.0.1"
VERSION = "1.0.0"
end
end
2 changes: 1 addition & 1 deletion spec/fixtures/links.json
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"links":{"pages":{"first":"https://api.example.com/v1/servers?page=1&per_page=1","prev":"https://api.example.com/v1/servers?page=1&per_page=1","last":"https://api.example.com/v1/servers?page=3&per_page=1","next":"https://api.example.com/v1/servers?page=3&per_page=1"}}}
{"links":{"self":"https://api.example.com/v1/servers?page%5Bnumber%5D=2&page%5Bsize%5D=1","first":"https://api.example.com/v1/servers?page%5Bnumber%5D=1&page%5Bsize%5D=1","prev":"https://api.example.com/v1/servers?page%5Bnumber%5D=1&page%5Bsize%5D=1","next":"https://api.example.com/v1/servers?page%5Bnumber%5D=3&page%5Bsize%5D=1","last":"https://api.example.com/v1/servers?page%5Bnumber%5D=3&page%5Bsize%5D=1"}}
1 change: 1 addition & 0 deletions spec/fixtures/links_with_additional_params.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"links":{"self":"https://api.example.com/v1/servers?page%5Bnumber%5D=2&page%5Bsize%5D=1&test=test","first":"https://api.example.com/v1/servers?page%5Bnumber%5D=1&page%5Bsize%5D=1&test=test","prev":"https://api.example.com/v1/servers?page%5Bnumber%5D=1&page%5Bsize%5D=1&test=test","next":"https://api.example.com/v1/servers?page%5Bnumber%5D=3&page%5Bsize%5D=1&test=test","last":"https://api.example.com/v1/servers?page%5Bnumber%5D=3&page%5Bsize%5D=1&test=test"}}
37 changes: 24 additions & 13 deletions spec/jbuilder/pagination/pages_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@

describe 'Jbuilder#pages!' do
context 'when there is pagination for collection' do
let(:collection) { OpenStruct.new(current_page: 2, total_pages: 3, per_page: 1) }
let(:collection) { OpenStruct.new(current_page: 2, total_pages: 3, size: 1) }
let(:response_json) { File.read("spec/fixtures/links.json").chomp }

it "returns full link pagination" do
expect(build_json_for(collection)).to eq(response_json)
end
it { expect(build_json_for(collection)).to eq(response_json) }
end

context 'when there is additional params' do
let(:collection) { OpenStruct.new(current_page: 2, total_pages: 3, size: 1) }
let(:response_json) { File.read("spec/fixtures/links_with_additional_params.json").chomp }
let(:additional) { { test: 'test' } }

it { expect(build_json_for(collection, query_parameters: additional )).to eq(response_json) }
end

context 'when there is no pagination for collection' do
let(:collection) { OpenStruct.new(current_page: 1, total_pages: 1) }
let(:collection) { OpenStruct.new(current_page: 1, total_pages: 1, size: 1) }
let(:response_json) { {links: {self: "https://api.example.com/v1/servers?page%5Bnumber%5D=1&page%5Bsize%5D=1" } }.to_json }

it "returns empty link pagination" do
expect(build_json_for(collection)).to eq("{}")
end
it { expect(build_json_for(collection)).to eq(response_json) }
end

context 'when collection is nil' do
it "returns empty link pagination" do
expect(build_json_for(nil)).to eq("{}")
end
it { expect(build_json_for(nil)).to eq("{}") }
end

context 'when there is a collection but it does not respond to all methods required' do
let(:collection) { OpenStruct.new(current_page: 1, total_pages: 1) }

it { expect(build_json_for(collection)).to eq("{}") }
end

def build_json_for(collection)
def build_json_for(collection, options = {})
Jbuilder.encode do |json|
json.links do
json.pages! collection, url: "https://api.example.com/v1/servers"
json.pages! collection,
url: "https://api.example.com/v1/servers",
query_parameters: options.fetch(:query_parameters, {})
end
end
end
Expand Down