ページネーション　同期　非同期

#はじめに

- railsアプリで[gem "kamianri"](https://github.com/kaminari/kaminari)を用いて、ページネーション機能を実装してみようと思います。
- 今回使ったアプリ→https://github.com/shotaimai66/users

#想定機能

- ユーザー一覧(index)を表示するページの実装
- ユーザーの表示数は３人で設定
- 同期処理、非同期処理両方実装

#環境
- AWScloud9
- Rails 5.2.2
- ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
- [gem "kamianri"](https://github.com/kaminari/kaminari)



#実装 (同期処理)
###前提
ユーザーの一覧ページはできているものとします。以下画像。
![screencapture-127050231590404798fc13feefda8876-vfs-cloud9-us-east-2-amazonaws-users-2019-01-13-16_34_41.jpg](https://qiita-image-store.s3.amazonaws.com/0/270321/34f4c98e-1683-432a-b7e5-90b515f4c256.jpeg)

###gem "kamianri" インストール

```ruby:Gemfile
gem 'kaminari'
```

```irb_output:コマンド
bundle install
```

###コントローラー修正
```ruby:app/controllers/users_controller.rb
  def index
    @users = User.page(params[:page]).per(3).all
  end
```
###ビュー修正
```erb:app/views/users/index.html.erb
<div id="pagenate">
  <p id="notice"><%= notice %></p>
  
  <h1>Users</h1>
  <h3>ユーザー数：<%= @users.size %></h3>
  
  <table class="table table-striped">
    <thead>
      <tr>
        <th>ID</th>
        <th>名前</th>
        <th>年齢</th>
        <th>性別</th>
        <th colspan="3"></th>
      </tr>
    </thead>
  
    <tbody>
      <% @users.each do |user| %>
        <tr>
          <td><%= user.id %></td>
          <td><%= user.name %></td>
          <td><%= user.age %></td>
          <td><%= user.sex %></td>
          <td><%= link_to 'Show', user %></td>
          <td><%= link_to 'Edit', edit_user_path(user) %></td>
          <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
  <%= paginate @users %>
  <br>
</div>
<%= link_to 'New User', new_user_path %>

```
###同期処理完成
- 同期処理でのページネーションはめっちゃ簡単ですね。gemの力は絶大です。ですが、頼りすぎは禁物ですね。

#実装（非同期処理）
###コントローラー修正
```ruby:app/controllers/users_controller.rb
  def index
    @users = User.page(params[:page]).per(3).all
    
    respond_to do |format|
      format.html
      format.js
    end
    
  end
```
- コントローラーのindexアクションで最後に`format.js`が評価され、jsフォーマットが返される。そして、`index.js.erb`を探しに行きます

###JSビュー作成
```erb:app/views/users/index.js.erb
  $('#pagenate').html("<%= escape_javascript(render 'index_page') %>");
```
- index.js.erbでは、htmlメソッドで`<%=render 'index_page'%>`をidがpagenateのdiv要素にレタリングされます。
- 次にパーシャルの`_index_page.html.erb`を作成します。

###パーシャル作成
```erb:app/views/users/_index_page.html.erb
  <p id="notice"><%= notice %></p>
  
  <h1>Users</h1>
  <h3>ユーザー数：<%= @users.size %></h3>
  
  <table class="table table-striped">
    <thead>
      <tr>
        <th>ID</th>
        <th>名前</th>
        <th>年齢</th>
        <th>性別</th>
        <th colspan="3"></th>
      </tr>
    </thead>
  
    <tbody>
      <% @users.each do |user| %>
        <tr>
          <td><%= user.id %></td>
          <td><%= user.name %></td>
          <td><%= user.age %></td>
          <td><%= user.sex %></td>
          <td><%= link_to 'Show', user %></td>
          <td><%= link_to 'Edit', edit_user_path(user) %></td>
          <td><%= link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } %></td>
        </tr>
      <% end %>
    </tbody>
  </table>
  <%= paginate @users, remote: true %>
  <br>
```

###index.html.erb修正
```erb:app/views/users/index.html.erb
上記省略

 </table>
##以下のerbに`remote: true`を追記
  <%= paginate @users, remote: true %>
  <br>
</div>
<%= link_to 'New User', new_user_path %>
```
- `<%= paginate @users, remote: true %>`とすることで非同期で処理をするという命令になります。

###完成！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/270321/35106bc4-2a87-f603-b301-28cca3f1fb50.png)



#解説
##respond_to do |format|~end
- indexアクションの`respond_to　〜ブロック〜`では、指定されたフォーマット形式で@userの情報を返しています。例えば以下のように、indexアクションを修正すると、`/users.json`にアクセスすると以下のような情報が得られます。

```ruby:app/controllers/users_controller.rb
  def index
    @users = User.all.page(params[:page]).per(3)
    
    respond_to do |format|
      format.html
      format.js
      format.json { render :json => @users }
      format.xml  { render :xml => @users }
    end
  end
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/270321/ee7a8aff-e07b-ec0d-a94c-430525533147.png)
- `/users.xml`にアクセスすると以下のようにXML形式の@usersの情報が得られます。
 ![image.png](https://qiita-image-store.s3.amazonaws.com/0/270321/5ba70573-0050-1852-32f6-aea22adeea85.png)
- 同じようにhtml、jsも情報を送っている。jsに限っては,アクセスしてもエラーになってしまいます。
- 作成した機能を例にとれば、実際の非同期の流れは、
`index.html.erb→` `indexアクション→``index.js.erb→``_index.page.html.erb`という感じになります。

##index.js.erb
```erb:app/views/users/index.js.erb
  $('#pagenate').html("<%= escape_javascript(render 'index_page') %>");
```
- 上のjsコードは`idがpagenateの要素に、htmlメソッドを使って、　<%= render 'index_page' %>`を挿入するという意味です。
- htmlメソッドは、任意の要素に指定した、htmlを挿入するjavascriptのメソッドです。
- escape_javascriptは、javascriptのエスケープメソッドですね。jsコードの中では、erb文は直接かけないので、こういう書き方になります。


#まとめ
少し長くなりましたが、ほんとに簡単にできました。
さらに便利なkaminariメソッド群は公式へ→https://github.com/kaminari/kaminari