概要
- Rails 5.1 + Vue.js + Webpacker を使ってフロント開発を行う
- 前回の記事では開発環境の構築を行った
- Rails 5.1 + Vue.js で開発を行う - part1 環境構築
- 本記事では、Ajax 通信で、GET して Rails の View にいろいろ表示していきたい。
- 全コードはこちらより確認いただけます
作るアプリ
- 図書管理アプリを作ることにする
- 本を保存したり、情報を参照するようなアプリを作る
開発の流れ
実際に開発する前に開発の流れを紹介しておきます。
- Ajax で GET する方法を実装したいので、はじめに seed で DB に本の各種情報を保存しておきます
- その後に、Vue を使って本の情報を取得したいと思います。
準備 | DB にデータを保存する
書籍のデータを作成していきたいと思います。
Book モデルの作成
Book モデルを作成します。
DB には、タイトル、筆者、出版社、ジャンルを保存しようと思います。
$ rails g model Book title:string author:string publisher:string genre:string
$ rake db:migrate
ダミーデータの作成
gem 'faker'
$ bundle install
20.times do
Book.create(
title: Faker::Book.title,
author: Faker::Book.author,
publisher: Faker::Book.publisher,
genre: Faker::Book.genre
)
end
$ rake db:seed
Rails View で表示する
Rails の View で先程の情報を表示します。
class BooksController < ApplicationController
def index
@books = Book.all
end
end
.container
.row
- @books.each do |book|
.col.s4.m6
.card
%span.card-title
= book.title
こんな感じで表示されます
(Materialize csss を使っていると...)
Ajax で本の情報を取得する
Ajax で情報を取得する際にどのように取得するのか考える必要がある。
選択肢は
- ページローディング時にすべての情報を取得する
- ページローディング後にユーザのアクションがあったときに情報を取得する
- ページローディング時にすべての情報を取得する
の方法は一番楽な手段だが、2 のほうが動作が軽く、ユーザが必要な情報だけを表示できる合理的な手段である。
そして、1 に関しては Rails で十分に表現できる範囲なので、今回はせっかくなので 2 で行いたいと思う。
具体的には、ページローディング時には、Rails 側で本のタイトルだけを表示しておき、 詳細
ボタンをユーザが押すと、Ajax で本の詳細情報を取得して表示する、みたいなことをやっていきたい。
API の作成
Ajax で GET しようと思うと、API を作成して、そこにリクエストを投げて JSON を取得することになります。
なので、はじめに API を作成しましょう。
各本の情報を取得するような API を作成していきます。
今回は jbuilder を使って API を作ろうと思います。
正直なところ、この程度のデータであれば jbuilder は不要なのですが複雑になってくると必要なので覚えておくと良かったりします。
routes
エンドポイントをわけるために、別のコントローラーを作成していきます。
Rails.application.routes.draw do
root to: 'page#home'
resources :books, only: %i(index)
+ namespace :api do
+ resources :books, only: %i(show)
+ end
end
controller
class Api::BooksController < ApplicationController
def show
@book = Book.find(params[:id])
render 'show', formats: 'json', handlers: 'jbuilder'
end
end
view
json.title @book.title
json.author @book.author
json.publisher @book.publisher
json.genre @book.genre
※ json.extract!
を使うほうがキレイだが、わかりやすくするために上記のようにした。
この状態で、ちゃんと json が返っているか確認しましょう。
api/books/1.json
にアクセスしてみてください。以下のような表示になったら、json が返ってきている証拠です。
もし返ってきていなければ、コンソールにてネットワークを確認してください。
エラー内容が表示されているかもしれません。
以下のような json が返っていれば問題ないです。
Ajax で GET しよう!
Vue で Ajax 通信する際に便利なライブリーである axios
をインストールします。
$ yarn add axios
本のタイトルをクリックしたときに、Ajax によって GET して Vue の data に値を代入することにします。
なので、card-title をクリックしたときに、Ajax で GET を行う setBookInfo
メソッド(後ほど定義します)を実行します。
View
-.container
+.container.js-booksIndex
.row
- @books.each do |book|
.col.s4.m6
.card
- %span.card-title
+ %span.card-title{'v-on:click': "setBookInfo(#{book.id})"}
= book.title
+ = javascript_pack_tag 'books/index'
Vue
el には 先程の View で指定した class を指定します。
methods には先程、説明しました setBookInfo()
を定義していきます。
タイトルをクリックしたときに、id を取得するので、引数には id
を入れておきます。
次に、axios を使って、get を行います。
すごく簡単です。get したい URL を以下のように指定するだけです。
あとは、返ってきた response
を Vue の data に代入してあげます。
import Vue from 'vue/dist/vue.esm';
import axios from 'axios';
new Vue({
el: '.js-booksIndex',
data: {
bookInfo: {},
},
methods: {
setBookInfo(id){
axios.get(`api/books/${id}.json`)
.then(res => {
this.bookInfo = res.data;
});
}
}
});
GET したデータを Rails View に表示する
タイトルをクリックしたら表示するようにしようと思います。
.container.js-booksIndex
.row
- @books.each do |book|
.col.s4.m6
.card
%span.card-title{'v-on:click': "setBookInfo(#{book.id})"}
= book.title
+ .row{'v-show': 'bookInfoBool'}
+ .col.s12.m12
+ .card.blue-grey.darken-1
+ .card-content.white-text
+ %span.card-title
+ {{ bookInfo.title }}
+ .detail
+ {{ bookInfo.author }}
+ .detail
+ {{ bookInfo.publisher }}
+ .detail
+ {{ bookInfo.genre }}
= javascript_pack_tag 'books/index'
表示条件をコントロールする bookInfoBool
を定義します。
Rails の View 側にて、 {'v-show': 'bookInfoBool'}
というふうにしておくと、 bookInfoBool == true
の場合のみ表示されるようになります。
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;
});
}
}
});
Ajax で Get できれば表示されるので、get が成功したときに bookInfoBool = true
にします。
以上のコードを追加すると、以下のようになると思います。