6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Rails+Vue.js]に係るCRUD入門〜Part3: Vue Router設定編〜

Last updated at Posted at 2019-08-17

Rails+Vue.js+Webpackerによる「Create, Read, Update, Destroy」処理のチュートリアルを記述する。
なお,前提知識として,Railsチュートリアル終了程度を想定する。

<概要>

■ 本記事の内容

  • 前回作成したViewをVueのコンポーネントへ移行する。
  • SPAに必要なVue Routerを設定する。
  • ルーティング用のヘッダーを作成する。
  • 今回のコードは,GitHubのコミット履歴で確認可能である。
    • [前回分の修正]から[不要データの削除]まで
  • 本記事の参考URL

■ 記事共通

<本文>

■ 前回分の修正

前回のビューはERBで実装したが,今後はSPAによる実装を進めるため,ERBによる実装を削除し,ERBによるViewをVue.jsに置き換える作業を実施する。

○1:[App.vue]にビューの情報を転記

app/javascript/packs/App.vue
<template>
  <div class="container">
    <h1 class="#f3e5f5 purple lighten-5 center">[Rails+Vue.js]~Bookshelf~</h1>
    <div class="row #e3f2fd blue lighten-5">
      <div class="col s4 m6" v-for="book in books">
        <div class="card btn">
          <span class="card-title" v-on:click="setBookInfo(book.id)">
            {{ book.title }}
          </span>
        </div>
      </div>
    </div>
    <div class="row" v-show="bookInfoBool">
      <div class="col s12 m12">
        <div class="card blue-grey darken-1">
          <div class="card-content white-text">
            <span class="card-title">{{ bookInfo.title }}</span>
            <div class="detail">
              ・著者:{{ bookInfo.author }}
            </div>
            <div class="detail">
              ・出版社:{{ bookInfo.publisher }}
            </div>
            <div class="detail">
              ・ジャンル:{{ bookInfo.genre }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import Vue from 'vue'
  import axios from 'axios'

  export default {
    name: 'BookHome',
    data: function() {
      return {
        bookInfo: {},
        bookInfoBool: false,
        books: [],
      }
    },
    mounted: function() {
      this.fetchBooks();
    },
    methods: {
      fetchBooks() {
        axios.get('/api/books').then((res) => {
          for(var i = 0; i < res.data.books.length; i++) {
            this.books.push(res.data.books[i]);
          }
        }, (error) => {
          console.log(error);
        });
      },
      setBookInfo(id){
        axios.get(`api/books/${id}.json`).then(res => {
          this.bookInfo = res.data;
          this.bookInfoBool = true;
        });
      }
    }
  }
</script>

<style scoped></style>
  • Rubyのコードも含まれているため,該当部分を次の事項のとおり修正

  • [v-for="book in books"]

    • [books]に格納された各情報について,[book]にそれぞれ格納し,定義した要素内で展開する。
    • Rubyだと[books.each { |book| book.title }]と同値である。
  • [mounted: function(){}]

    • Vueインスタンスのマウント直後に実行される。
  • [fetchBooks(){}]

    1. [axios.get('/api/books')]により,Railsから情報を受け取り,
    2. [for(var i = 0; i < res.data.books.length; i++) { this.books.push(res.data.books[i]) }]で,受け取った情報をbooksに順次格納する。
  • 参考URL

○2:APIの作成

app/controllers/api/books_controller.rb
class Api::BooksController < ApplicationController
  def index
    @books = Book.all
    render 'index', formats: 'json', handlers: 'jbuilder'
  end
...
end
app/views/api/books/index.json.jbuilder
json.set! :books do
  json.array! @books do |book|
    json.extract! book, :id, :title
  end
end

○3:ルーティングの修正

config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'

  namespace :api do
    resources :books, only: [:index, :show]
  end
end
  • ERBのルーティングを削除

○4:動作確認

  • ここまでで,前回と同じ動作になると成功です。

■ Vue Routerの設定

○1:Vue Routerを導入
Vue Routerにより,登録されたパスとコンポーネントで,画面内を差し替えること可能にするSPAの要となるライブラリである。

.bash
$ yarn add vue-router

○2:[App.vue]を修正

app/javascript/packs/App.vue
<template>
  <div id="app">
    <router-view/>
  </div>
</template>

<script>
  export default {
    name: 'App',
  }
</script>

<style scoped></style>
  • [router-view]:router.jsで登録されたコンポーネントが表示される場所
  • [name: 'App']:VueDevtoolsにおけるコンポーネントの識別名称
  • 参考URL

○3:[router.js]を作成

app/javascript/router/router.js
import Vue          from 'vue'
import VueRouter    from 'vue-router'
import BookHome     from '../pages/BookHome.vue'

Vue.use(VueRouter)

const routes = [
  { path: '/',  name: 'BookHome', component: BookHome },
];

export default new VueRouter({ routes });

○4:[application.js]を修正

app/javascript/packs/application.js
import Vue    from 'vue'
import App    from './App.vue'
import Router from '../router/router.js'

const app = new Vue({
   el: '#app',
   router: Router,
   render: h => h(App)
})

○5:[BookHome.vue]を作成

app/javascript/pages/BookHome.vue
<template>
  <div class="container">
    <h1 class="#f3e5f5 purple lighten-5 center">[Rails+Vue.js]~Bookshelf~</h1>
    <div class="row #e3f2fd blue lighten-5">
      <div class="col s4 m6" v-for="book in books">
        <div class="card btn">
          <span class="card-title" v-on:click="setBookInfo(book.id)">
            {{ book.title }}
          </span>
        </div>
      </div>
    </div>
    <div class="row" v-show="bookInfoBool">
      <div class="col s12 m12">
        <div class="card blue-grey darken-1">
          <div class="card-content white-text">
            <span class="card-title">{{ bookInfo.title }}</span>
            <div class="detail">
              ・著者:{{ bookInfo.author }}
            </div>
            <div class="detail">
              ・出版社:{{ bookInfo.publisher }}
            </div>
            <div class="detail">
              ・ジャンル:{{ bookInfo.genre }}
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
  import axios from 'axios'

  export default {
    name: 'BookHome',
    data: function() {
      return {
        bookInfo: {},
        bookInfoBool: false,
        books: [],
      }
    },
    mounted: function() {
      this.fetchBooks();
    },
    methods: {
      fetchBooks() {
        axios.get('/api/books').then((res) => {
          for(var i = 0; i < res.data.books.length; i++) {
            this.books.push(res.data.books[i]);
          }
        }, (error) => {
          console.log(error);
        });
      },
      setBookInfo(id){
        axios.get(`api/books/${id}.json`).then(res => {
          this.bookInfo = res.data;
          this.bookInfoBool = true;
        });
      }
    }
  }
</script>

<style scoped></style>
  • 修正前の[App.vue]をそのまま転記
  • [router-view]に差し込まれるコンポーネント

■ Headerの設定

 次の記事で本の登録機能を作成するため,ここでルーティング用のヘッダーを作成しておく。

○1:[components]フォルダ及び[Header.vue]を作成

app/javascript/components/Header.vue
<template>
   <div>
     <nav>
       <div class="nav-wrapper">
         <router-link to="/" class="brand-logo">Bookshelf</router-link>
         <ul id="nav-mobile" class="right">
           <li><router-link to="">本の登録</router-link></li>
         </ul>
       </div>
     </nav>
   </div>
</template>

<script></script>
<style scoped></style>

○2:[App.vue]を修正

app/javascript/packs/App.vue
<template>
  <div id="app">
    <Header/>
    <router-view/>
  </div>
</template>

<script>
  import Header from '../components/Header.vue'
  export default {
    name: 'App',
    components: {
      Header
    },
  }
</script>

<style scoped></style>

■ 不要データの削除

  • [app/javascript/packs/book.js]:削除
  • [app/views/books]:削除
  • [app/controllers/books_controller.rb]:削除

〜Part3:Vue Router設定編終了〜
〜Part4:Create, Update, Delete編へ進む〜

6
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?