【RailsAPI + Vue.js】Pagyを用いたページネーションの実装
はじめに
RailsAPIとVuetifyでページネーションを作りました。
gemをどれにしようか調べてみたところ、Pagyがやたらとシンプル!軽い!ということらしいので、Pagyを使いました。
環境、使用技術
- Rails 5.2.4.2
- Pagy 3.8.1
- Vue.js 4.3.1
- Vuetify 2.2.21
- axios 0.19.2
Vuetifyは他のものでも置き換え可能かなと思います。
Rails側
Pagyの初期設定
How To | Pagyに書いてある通りです。
gem 'pagy', '~> 3.5'
毎度おなじみ$ bundle install
を実行し、config/initializers/pagy.rb
に設定ファイルを作成します。
テンプレートをコピペして、必要なところだけコメントアウトを外します。
Pagy::VARS[:items] = 3 # 1ページに3件取得する
コントローラ
class Api::V1::UsersController < Api::V1::BaseController
+ include Pagy::Backend
def index
- users = User.all
+ pagy, users = pagy(User.all)
render json: users
end
end
PostmanでAPIを叩いてレスポンスを確認してみます。
このように、userのデータが3件ずつ取得できていました(シリアライザーを使っているので、カラム名がキャメルケースになっています)。
しかし、これだけでは現在のページや総ページ数がわかりません。フロント側のページネーションコンポーネントではそれらのデータが必要なので、追加で記述していきます。
ヘッダーにページの情報を入れる
+ require 'pagy/extras/headers'
class Api::V1::UsersController < Api::V1::BaseController
include Pagy::Backend
def index
pagy, users = pagy(User.all)
+ pagy_headers_merge(pagy)
render json: users
end
end
この記述により、レスポンスヘッダーに以下の情報が格納されます。
KEY |
---|
Link |
Current-Page |
Page-Items |
Total-Pages |
Total-Count |
"Link"の中身(実際は一行)↓
<http://127.0.0.1:3000/api/v1/users?page=1>; rel="first",
<http://127.0.0.1:3000/api/v1/users?page=1>; rel="prev",
<http://127.0.0.1:3000/api/v1/users?page=3>; rel="next",
<http://127.0.0.1:3000/api/v1/users?page=3>; rel="last"
これでRails側の処理は終わりです。
共通化する場合は、after_action
を使う方法もあります(see 公式)。
Vue側
Vue-routerは使っていません。
テンプレート部分
Pagination component — Vuetify.jsを少しカスタマイズします。
<template>
<div class="text-center">
<v-pagination
v-model="currentPage"
:length="page.totalPages"
></v-pagination>
</div>
</template>
<script>
export default {
data () {
return {
requestUrl: "/api/v1/users",
page: {
currentPage: 1,
totalPages: 5,
}
}
},
}
</script>
これでひとまずページネーションを表示することはできましたが、まだ、ボタンを押してもpage.currentPage
の値が変わるだけです。
ボタンを押したときの挙動
コンポーネントから@input
イベントを受け取り、changePage
メソッドで処理を行います。
<template>
<div class="text-center">
<v-pagination
v-model="currentPage"
:length="page.totalPages"
+ @input="changePage"
></v-pagination>
</div>
</template>
<script>
export default {
data () {
return {
+ requestUrl: "/api/v1/users",
page: {
currentPage: 1,
totalPages: 5,
}
}
},
+ methods: {
+ changePage(val) {
+ // 処理
+ }
+ }
}
</script>
methods: {
async changePage(val) {
// "/api/v1/users?page=2"などにGETリクエストを送る
const response = await this.$axios.get(`${this.requestUrl}?page=${val}`)
// 受け取ったusersデータを格納する
const { users } = response.data
this.users = users
}
}
ページ読み込み時のデータ取得
mounted
で最初の画面描画時の動きを記述します。
async mounted() {
try {
// "/api/v1/users"にGETリクエストを送る
const response = await this.$axios.get(this.requestUrl)
// それぞれのdataにレスポンスの値を代入する
this.page.totalPages = Number(response.headers["total-pages"])
const { users } = response.data
this.users = users
}
}
最終的なコード
<template>
<!-- usersの表示部分。省略 -->
<div class="text-center">
<v-pagination
v-model="page.currentPage"
:length="page.totalPages"
@input="changePage"
/>
</div>
</template>
<script>
import goTo from "vuetify/es5/services/goto" // しれっと追加している
export default {
data() {
return {
requestUrl: "/api/v1/users",
page: {
currentPage: 1,
totalPages: 1,
},
users: []
}
},
async mounted() {
try {
const response = await this.$axios.get(this.requestUrl)
this.page.totalPages = Number(response.headers["total-pages"])
const { users } = response.data
this.users = users
}
},
methods: {
async changePage(val) {
goTo(0) // ページ最上部までスクロール。Vuetifyのメソッド
const res = await this.$axios.get(`${this.requestUrl}?page=${val}`)
const { users } = res.data
this.users = users
}
}
}
</script>
ちなみに
追加でヘッダーに情報を渡す場合
以下のように書くことで追加できます。requestUrl
を初期値のdataで設定するのが難しい場合は、このようにヘッダーに渡して受け取る方法もあります。
def index
pagy, users = pagy(User.all)
pagy_headers_merge(pagy)
response.headers.merge!({ 'Request-Url' => request.path_info })
render json: users
end
参考リンク
rails APIでページネーションを実装する
【vue.js】 Vuetifyで簡単ページネーション(Paginations)
Author And Source
この問題について(【RailsAPI + Vue.js】Pagyを用いたページネーションの実装), 我々は、より多くの情報をここで見つけました https://qiita.com/aiandrox/items/2034a4e90efa3e09b0b4著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .