Rails + Vue.js로 페이지 네이션이있는 테이블 만들기

개요


  • 업무에서 페이지 네이션 기능을 구현했으므로 거의 그대로의 구성으로 순서를 소개
  • 사용한 기술은 kaminari(Rails)Vuetify(Vue.js)
  • api를 통해 데이터를 검색하고 페이지 네이션으로 표시합니다.
  • 소스 코드

  • Rails의 개발 환경은 특별히 설명하지 않지만 다음 기사를 참고로 구축했습니다.
    Rails 6 + MySQL on Docker 환경을 초속으로 구축

    Book 모델 정의 및 샘플 데이터 작성



    이번에는 데이터베이스에 저장된 Book 목록을 api로 가져옵니다.
    먼저 Book 모델을 만들어 보겠습니다.
    # マイグレーションファイルの作成
    bin/rails g model Book name:string
    
    # マイグレーションを実行し、Booksテーブルを作成
    bin/rails db:migrate
    
    db/seeds.rb 를 편집하여 샘플 데이터 만들기

    db/seeds.rb
    100.times do |n|
      name  = "example-#{n+1}"
      Book.create!(name: name)
    end
    

    seed 실행
    bin/rails db:seed
    

    이제 Book 레코드가 100개 작성되었습니다.

    kaminari 설치 및 도서 목록 검색을위한 api 만들기



    Book 테이블에서 데이터를 검색할 때 kaminari를 사용합니다.
    kaminari 설치
    htps : // 기주 b. 코 m/카미나리/카미나리

    Gemfile
    # kaminariを追記
    gem 'kaminari'
    
    # kaminariのインストール。インストール完了後にサーバーを再起動させましょう
    bundle
    
    app/controllers/api/books_controller.rb를 만들고 책 목록을 반환하는 api를 구현합니다.

    app/controllers/api/books_controller.rb
    class Api::BooksController < ApplicationController
      def index
        # 表示するページの番号を指定
        page = params[:page] || 1
    
        # 1ページあたりの表示件数を指定
        per = params[:per] || 10
    
        # ページネーションで指定レコードを取得
        books = Book.page(page).per(per)
    
        # ページネーションした時の全ページ数
        total_pages = books.total_pages
    
        # レスポンスデータの定義
        response = {
          # bookレコードはidとnameフィールドのみ表示する
          books: books.select(:id, :name),
          total_pages: total_pages
        }
    
        # json形式でレスポンスを返却
        render json: response
      end
    end
    

    config/routes.rb
    Rails.application.routes.draw do
      # Book一覧取得用のパス
      get '/api/books', to: 'api/books#index'
    
      # Book一覧表示用のパス
      get '/books', to: 'books#index'
    end
    
    http://localhost:3000/api/books에 액세스하면 다음과 같은 json이 반환됩니다.



    도서 목록 표시 페이지 만들기



    도서 목록 표시를 위한 페이지를 만듭니다.
    Vuetify의 v-data-tableコンポーネントv-pagination를 사용하여 Axios로 api를 두드리십시오.
    ※ 여기에서는 번거로움을 피하기 위해 CDN 경유로 환경 구축을하고 있습니다. 적절하게 자신의 환경에 맞춘 환경 구축을 실시해 주세요

    app/views/layouts/application.html.erb
    <!DOCTYPE html>
    <html>
      <head>
        <title>AppName</title>
        <%= csrf_meta_tags %>
        <%= csp_meta_tag %>
    
        <%# CDNで Vue.js, Vuetify, Axios をインストールする %>
        <link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
        <link href="https://cdn.jsdelivr.net/npm/@mdi/[email protected]/css/materialdesignicons.min.css" rel="stylesheet">
        <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">
        <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
    
        <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
      </head>
    
      <%# ここも追加 %>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
      <body>
        <%= yield %>
      </body>
    </html>
    

    app/views/books/index.html.erb
    <div id="app">
      <v-app>
        <v-container>
          <h2>Book一覧</h2>
          <%# テーブル作成用コンポーネント %>
          <v-data-table
            :headers="headers"
            :items="items"
            :items-per-page="itemsPerPage"
            hide-default-footer
          />
        </v-container>
        <%# ページネーション表示用コンポーネント %>
        <v-pagination
          v-model="currentPage"
          :length="totalPages"
          <%# ページを変更した時にfetchBooksを呼び出す %>
          @input="fetchBooks"
        />
      </v-ap>
    </div>
    
    <script>
      new Vue({
        el: "#app",
        vuetify: new Vuetify(),
        data() {
          return {
            // テーブルのヘッダー情報。valueの値がレコードのフィールド名に紐付く
            headers: [
              { text: "ID", value: "id"},
              { text: "本の名前", value: "name"},
            ],
            // テーブルのボディー情報。apiで取得したBook一覧をここに格納する
            items: [],
            // 表示するページの番号
            currentPage: 1,
            // 1ページあたりの表示件数
            itemsPerPage: 10,
            // ページネーションした時の全ページ数
            totalPages: null,
          }
        },
        methods: {
          // AxiosでBook取得apiにリクエストを送る
          fetchBooks() {
            const url = `/api/books?page=${this.currentPage}?per=${this.itemsPerPage}`;
            axios
              .get(url)
              .then(res => {
                // Book一覧を取得
                this.items = res.data.books;
                // ページネーションした時の全ページ数を取得
                this.totalPages = res.data.total_pages;
            })
          }
        },
        // DOMが作成された時に fetchBooks を呼び出す
        created() {
          this.fetchBooks()
        },
      });
    </script>
    
    http://localhost:3000/books이것으로 페이지 네이션이 완료됩니다.
    아래와 같이 페이지를 전환할 때마다 표시가 바뀌면 OK입니다!



    좋은 웹페이지 즐겨찾기