LoginSignup
12
13

More than 3 years have passed since last update.

[Rails+Vue.js]に係るCRUD入門〜Part2: Read編〜

Last updated at Posted at 2019-08-17

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

<概要>

■ 本記事の内容

  • ViewをERB,API通信をVue.jsにより,本の詳細情報に係る表示機能を実装する。
  • 今回のコードは,GitHubのコミット履歴で確認可能である。
    • [Bookモデル及びデータベースを生成]から[APIを使用したRead機能を実装]まで

■ 記事共通

<本文>

■ Bookモデル及びデータベースを生成

$ rails g model Book title:string author:string publisher:string genre:string
db/migrate/[time_stump]_create_books.rb
class CreateBooks < ActiveRecord::Migration[5.2]
  def change
    create_table :books do |t|
      t.string :title, null: false
      t.string :author, null: false
      t.string :publisher, null: false
      t.string :genre, null: false

      t.timestamps
    end
  end
end
app/models/book.rb
class Book < ApplicationRecord
  validates :title, presence: true, length: { maximum: 100 }
  validates :author, presence: true, length: { maximum: 100 }
  validates :publisher, presence: true, length: { maximum: 50 }
  validates :genre, presence: true, length: { maximum: 50 }
end
$ rails db:migrate
  • 本の登録情報として,タイトル,著者,出版社,ジャンルを登録する。
  • テーブルにバリデーションを設定しておく。
  • 参考URL

■ 本のサンプルデータを作成

○1: Gem[faker]をGemfileに追加

Gemfile
...
gem 'materialize-sass'
gem 'material_icons'
gem 'faker'
...
$ bundle install

○2: サンプルデータを登録

config/seeds.rb
20.times do
  Book.create!(
    title: Faker::Book.title,
    author: Faker::Book.author,
    publisher: Faker::Book.publisher,
    genre: Faker::Book.genre
  )
end
$ rails db:migrate

■ Booksコントローラを生成し,本情報を表示

$ rails g controller Books index
config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  resources :books, only: [:index]
end
app/controllers/books_controller.rb
class BooksController < ApplicationController
  def index
    @books = Book.all
  end
end
app/views/books/index.html.erb
<div class="container">
  <h1 class="#f3e5f5 purple lighten-5 center">[Rails+Vue.js]~Bookshelf~</h1>
  <div class="row #e3f2fd blue lighten-5">
    <% @books.each do |book| %>
      <div class="col s4 m6">
        <div class="card">
          <span class="card-title">
            <%= book.title %>
          </span>
        </div>
      </div>
    <% end %>
  </div>
</div>
  • この時点で次の画像のように表示されると成功です。 image.png

■ APIの生成

○1: APIの送信元を作成

$ rails g controller api::books
config/routes.rb
Rails.application.routes.draw do
...
  namespace :api do
    resources :books, only: [:show]
  end
end
app/controllers/api/books_controller.rb
class Api::BooksController < ApplicationController
  def show
    @book = Book.find(params[:id])
    render 'show', formats: 'json', handlers: 'jbuilder'
  end
end
app/views/api/books/show.json.jbuilder
json.id        @book.id
json.title     @book.title
json.author    @book.author
json.publisher @book.publisher
json.genre     @book.genre

# 次のコードと同等です。
# json.extract! @book, :id, :title, :author, :publisher, :genre

○2: 実装を確認

{"id":1,"title":"ヤマノススメ","author":"しろ","publisher":"アース・スター エンターテイメント","genre":"アウトドア"}

■ API通信を実現するライブラリを導入

$ yarn add axios

■ APIを使用したRead機能を実装

○1: Vue.js側のエントリーポイントを作成

app/javascript/packs/book.js
import Vue from 'vue/dist/vue.esm';
import axios from 'axios';

new Vue({
  el: '.js-booksIndex',
  data: {
    bookInfo: {},
    bookInfoBool: false
  },
  methods: {
    setBookInfo(id){
      axios.get(`api/books/${id}.json`).then(res => {
        this.bookInfo = res.data;
        this.bookInfoBool = true;
      });
    }
  }
});
  • [el: '.js-booksIndex']:book.jsの対象範囲
  • [data.bookInfo]:表示する本の詳細情報
  • [data.bookInfoBool]:情報の表示有無を判定(デフォルトで非表示設定)
  • [setBookInfo(id):詳細情報を表示するメソッド
    1. [axios.get(api/books/${id}.json)]により,APIを受け取り,
    2. [this.bookInfo = res.data;]により,本情報をdataに格納し,
    3. [this.bookInfoBool = true;]により,非表示を表示に変更して,詳細情報が表示される。

○2: Rails側のViewを作成

app/views/books/index.html.erb
+ <div class="container js-booksIndex">
  <h1 class="#f3e5f5 purple lighten-5 center">[Rails+Vue.js]~Bookshelf~</h1>
  <div class="row #e3f2fd blue lighten-5">
    <% @books.each do |book| %>
      <div class="col s4 m6">
+         <div class="card btn">
+           <span class="card-title" v-on:click="setBookInfo(<%= book.id %>)">
            <%= book.title %>
          </span>
        </div>
      </div>
    <% end %>
  </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>
+ <%= javascript_pack_tag 'book' %>
  • [v-on:click="setBookInfo(<%= book.id %>)]
    • [v-on:click="~"]により,クリックした際の動作を指定する。
    • この場合,[book.js]の[setBookInfo(id)]が動作して,[data.bookInfo]にクリックした本の情報が格納される。
    • なお,[v-on:click]は,[@click]で省略可能である。
  • [v-show="bookInfoBool"]
    • [v-show="~"]により,中身がTrueの場合,要素が表示される。
    • この場合,[book.jsの[data.bookInfoBool]が参照され,表示有無が判定される。
  • 参考URL

○3: 実装を確認
02_Read:動作確認.gif

  • 上記のように動作したら成功である。
  • なお,現在のビューは,ERBを使用しているが,SPAによる実装を目指すため,次の記事で全てVueのコンポーネントに置き換える。

〜Part2:Read編終了〜
〜Part3:Vue Router設定編へ進む〜

12
13
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
12
13