kaminariのlast_page?の動作に気をつけて！

## 主旨と結論

連番で管理するのではなく、「前へ」「次へ」ボタンを設置しての運用です。
**記事のポイントは、データが入っていない状態でページネーション機能を使う際に気をつけること**
**常に何らかのデータが存在する場合は気にする必要はありません。**

下記を実現したい場合に参考になります。

- 最初のページは「前へ」ボタンを消す
- 最後のページは「次へ」ボタンを消す
- 最初で最後のページは両方とも消す**←ここで次へ問題が発生します。**

なので

当初問題のlast_page?の条件分岐は、

```erb
<% unless pagenates.last_page? %>
 <a href="<%= path_to_next_page(pagenates) %>">次のページ</a>
<% end %>
```

のようにしていました。
これだと、データがない状態では、最初で最後のページに**次へボタンが表示されてしまう**のです。


**最終的には下記のようにすればOK**

```erb
<% unless pagenates.last_page? || paenates.out_of_range %>
 <a href="<%= path_to_next_page(pagenates) %>">次のページ</a>
<% end %>
```


## まとめ
- last_page?は、現在ページと総ページ数が同じ時にtrueを返し、違う時にfalseを返す。
- データが存在しない際は、表示されるページ数(current_page)は、1となるが、total_pagesは、**0**となる。
- そのため、データが存在しない場合、表示されたページが最初で最後のページとなるものの条件分岐にはout_of_rangeを併用する必要がある。

**最初で最後のページの戻り値は下記の通り**

|メソッド       |データあり|データなし|
|---         |---    |---     |
|current_page|1      |1       |
|total_pages |1      |0       |
|last_page?  |true   |false   |
|first_page? |true   |true    |
|out_of_range|false  |true    |


## 解説

結論に書きましたが、last_page?は、最後のページの場合trueを返す、ではありません。
last_page?は、**現在ページと総ページ数が同じ時にtrueを返し、違う時にfalseを返す**です。

kaminariのソースを確認します。


```ruby
def last_page?
  current_page == total_page
end
```

これだけではよくわからないので、

- current_pageメソッド
- total_pageメソッド

を確認します。

## current_pageメソッド

```ruby
    def current_page
      offset_without_padding = offset_value
      offset_without_padding -= @_padding if defined?(@_padding) && @_padding
      offset_without_padding = 0 if offset_without_padding < 0

      (offset_without_padding / limit_value) + 1
    rescue ZeroDivisionError
      raise ZeroPerPageOperation, "Current page was incalculable. Perhaps you called .per(0)?"
    end
```

これは、offset_without_paddingの値が0になるのでしょうか。
データがないのでpaddingなど出ないはずです。
最後には、

```ruby
(offset_without_padding / limit_value) + 1
```
**として、0をlimit_valueで割って+1しているので、基本的に戻り値は1以上であることが想像できます。**

そして、下記の実行結果を確認すると、1とでていましたのでよしとしましょう。
お分かりの方コメント頂けると幸いです、、、、！！！

```erb

<%= @users.current_page %>
```

## total_pagesメソッド

```ruby
    def total_pages
      count_without_padding = total_count
      count_without_padding -= @_padding if defined?(@_padding) && @_padding
      count_without_padding = 0 if count_without_padding < 0

      total_pages_count = (count_without_padding.to_f / limit_value).ceil
      max_pages && (max_pages < total_pages_count) ? max_pages : total_pages_count
    rescue FloatDomainError
      raise ZeroPerPageOperation, "The number of total pages was incalculable. Perhaps you called .per(0)?"
    end
```

これも
count_without_paddingが0になるのはわかります。
あとは単純な計算とif文ですね。
戻り値がtotal_pages_countになるのはわかりますので、答えは0。(お分かりの方コメンry...)

そして、下記の結果は0でした。

```erb
<%= @users.total_pages %>
```




## まとめ、last_page?メソッドとout_of_rangeメソッド

```ruby
def last_page?
  current_page == total_page
end
```

データがない状態では、

- current_pageは1
- total_pageは0

となりますので、最初で最後のページで、last_page?を使って条件分岐してしまうと、falseが返ってきます。


そこで登場するのが

- out_of_rangeメソッド

これは

```ruby
    def out_of_range?
      current_page > total_pages
    end
```

なので、データがない状態ではtrueが返ってきます。
現在ページの方が合計ページを上回ることって普通ないと思うのですが、今回のようなケースを想定していたのでしょうか。


## git_hub、紹介したメソッドが定義されているページ
Git_Hub/kaminari
https://github.com/kaminari/kaminari/blob/c5186f5d9b7f23299d115408e62047447fd3189d/kaminari-core/lib/kaminari/models/page_scope_methods.rb