-
Notifications
You must be signed in to change notification settings - Fork 412
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
--- | ||
title: Out Of Range | ||
--- | ||
# Out Of Range Extra | ||
|
||
This extra allows for easy handling of out of range pages. It internally resques from the `Pagy::OutOfRangeError` offering a few different ready to use modes, quite useful for UIs and/or APIs. | ||
|
||
## Synopsys | ||
|
||
See [extras](../extras.md) for general usage info. | ||
|
||
In the Pagy initializer: | ||
|
||
```ruby | ||
require 'pagy/extras/out_of_range' | ||
|
||
# default :last_page (other options :empty_page and :exception ) | ||
Pagy::VARS[:out_of_range_mode] = :last_page | ||
``` | ||
|
||
## Files | ||
|
||
This extra is composed of the [out_of_range.rb](https://github.com/ddnexus/pagy/blob/master/lib/pagy/extras/out_of_range.rb) file. | ||
|
||
## Variables | ||
|
||
| Variable | Description | Default | | ||
| -------------------- | ------------------------------------------ | ------------ | | ||
| `:out_of_range_mode` | `:last_page`, `empty_page` or `:exception` | `:last_page` | | ||
|
||
As usual, depending on the scope of the customization, you have a couple of options to set the variables: | ||
|
||
As a global default: | ||
|
||
```ruby | ||
Pagy::VARS[:out_of_range_mode] = :empty_page | ||
``` | ||
|
||
For a single instance (overriding the global default): | ||
|
||
```ruby | ||
pagy(scope, out_of_range_mode: :empty_page) | ||
Pagy.new(count:100, out_of_range_mode: :empty_page) | ||
``` | ||
|
||
## Modes | ||
|
||
These are the modes accepted by the `:out_of_range_mode` variable: | ||
|
||
### :last_page | ||
|
||
This is the default mode. It is useful in apps with an UI, in order to avoid to redirect to the last page. | ||
|
||
Regardless the out of range page requested, Pagy will set the page to the last page and paginate exactly as if the last page has been requested. For example: | ||
|
||
```ruby | ||
# no exception passing an out of range page (Default mode :last_page) | ||
pagy = Pagy.newpag(count: 100, page: 100) | ||
|
||
pagy.out_of_range? #=> true | ||
pagy.vars[:page] #=> 100 (requested page) | ||
pagy.page #=> 5 (curentlast page) | ||
pagy.last == pagy.page #=> true | ||
``` | ||
|
||
### :empty_page | ||
|
||
This mode will paginate the actual requested page, which - being out of range - is empty. It is useful with APIs, where the client expects an empty set of results in order to stop requesting further pages. For example: | ||
|
||
```ruby | ||
pagy = Pagy.new(count: 100, page: 100, out_of_range_mode: :empty_page) | ||
|
||
pagy.out_of_range? #=> true | ||
pagy.vars[:page] #=> 100 (requested page) | ||
pagy.page #=> 100 (actual empty page) | ||
pagy.last == pagy.page #=> false | ||
pagy.last #=> 5 | ||
pagy.last == pagy.prev #=> true (the prev page is the last page relative to out of range page) | ||
pagy.next #=> nil | ||
pagy.offset #=> 0 | ||
pagy.items #=> 0 | ||
pagy.from #=> 0 | ||
pagy.to #=> 0 | ||
|
||
pagy.series #=> [1, 2, 3, 4, 5] (no string, so no current page highlighted in the UI) | ||
``` | ||
|
||
### :exception | ||
|
||
This mode raises the `Pagy::OutOfRangeError` as usual, so you can rescue from and do what is needed. It is useful when you need to use your own custom mode even in presence of this extra (which would not raise any error). | ||
|
||
## Methods | ||
|
||
### out_of_range? | ||
|
||
Use this method in order to know if the requested page is out of range. The original requested page is available as `pagy.vars[:page]` (useful when used with the `:last_page` mode, in case you want to give some feedback about the rescue to the user/client). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
class Pagy | ||
|
||
VARS[:out_of_range_mode] = :last_page | ||
|
||
def out_of_range?; @out_of_range end | ||
|
||
alias :create :initialize | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
grosser
Contributor
|
||
|
||
def initialize(vars) | ||
create(vars) | ||
rescue OutOfRangeError => e | ||
raise e if @vars[:out_of_range_mode] == :exception | ||
This comment has been minimized.
Sorry, something went wrong.
grosser
Contributor
|
||
@out_of_range = true | ||
if @vars[:out_of_range_mode] == :last_page | ||
@page = @last # set as last page | ||
elsif @vars[:out_of_range_mode] == :empty_page | ||
@offset = @items = @from = @to = 0 # vars relative to the actual page | ||
@prev = @last # the prev is the last page | ||
define_singleton_method(:series) do |size=@vars[:size]| | ||
This comment has been minimized.
Sorry, something went wrong.
grosser
Contributor
|
||
@page = @last # series for last page | ||
super(size).tap do |s| # call original series | ||
s[s.index(@page.to_s)] = @page # string to integer (i.e. no current page) | ||
@page = @vars[:page] # restore the actual page | ||
end | ||
end | ||
end | ||
This comment has been minimized.
Sorry, something went wrong.
grosser
Contributor
|
||
end | ||
|
||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
require 'pagy' | ||
require_relative '../../test_helper' | ||
require 'pagy/extras/out_of_range' | ||
|
||
SingleCov.covered! | ||
|
||
describe Pagy do | ||
|
||
let(:vars) {{ page: 100, count: 103, items: 10, size: [3, 2, 2, 3] }} | ||
let(:pagy) {Pagy.new(vars)} | ||
|
||
describe "variables" do | ||
|
||
it 'has vars defaults' do | ||
Pagy::VARS[:out_of_range_mode].must_equal :last_page | ||
end | ||
|
||
end | ||
|
||
describe "#out_of_range?" do | ||
|
||
it 'must be out_of_range?' do | ||
pagy.must_be :out_of_range? | ||
Pagy.new(vars.merge(page:2)).wont_be :out_of_range? | ||
end | ||
|
||
end | ||
|
||
|
||
describe "#initialize" do | ||
|
||
it 'initializes with out of range page' do | ||
pagy.must_be_instance_of Pagy | ||
pagy.page.must_equal pagy.last | ||
pagy.vars[:page].must_equal 100 | ||
end | ||
|
||
it 'raises OutOfRangeError in :exception mode' do | ||
proc { Pagy.new(vars.merge(out_of_range_mode: :exception)) }.must_raise Pagy::OutOfRangeError | ||
end | ||
|
||
it 'works in :empty_page mode' do | ||
pagy = Pagy.new(vars.merge(out_of_range_mode: :empty_page)) | ||
pagy.page.must_equal 100 | ||
pagy.offset.must_equal 0 | ||
pagy.items.must_equal 0 | ||
pagy.from.must_equal 0 | ||
pagy.to.must_equal 0 | ||
pagy.prev.must_equal pagy.last | ||
end | ||
|
||
end | ||
|
||
describe "#series singleton for :empty_page mode" do | ||
it 'computes series for last page' do | ||
This comment has been minimized.
Sorry, something went wrong.
grosser
Contributor
|
||
pagy = Pagy.new(vars.merge(out_of_range_mode: :empty_page)) | ||
series = pagy.series | ||
series.must_equal [1, 2, 3, :gap, 9, 10, 11] | ||
pagy.page.must_equal 100 | ||
end | ||
end | ||
|
||
end |
2 comments
on commit c52db2a
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks like it solves the issue, thanks!
A PR to discuss instead of a straight up release would have been nice though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
impatience :)
how about prepending a module and then calling super ?