SPAをRailsとvue.jsとDRFで作成する
はじめに
django rest frameworkでapiを作り, それを使用したSPAをruby on railsで作成します。
apiは下から2番目の項目 ソースにある「djangoのプロジェクト」
今回作成するSPAは 「railsのプロジェクト」になります。詰まった時の参考にどうぞ。
開発環境
- OS:
macOS Big Sur v11.5.2
- Python:
Python 3.0.6
- Django:
3.2.5
- ruby:
2.6.5
- Rails:
6.1.4.1
Djangoのプロジェクトを作成
別のプロジェクトとしてdjangoでAPIを実装
下から2番目の項目にあるソースにあるように「djangoのプロジェクト」を作成します。
下の2つの記事を行うことで作成します。
API実装
Django REST Frameworkを使って爆速でAPIを実装する
CORS設定
DRFを使って、APIエンドポイントをフロントエンドから叩く場合にはCORSの設定が必要
【drf】django-cors-headersを使ってCORS設定を行う
動作確認
# 開発サーバーを起動
$python manage.py runserver
管理画面に入り,EntrysとUsersをいくつか作っておく
でEntryの情報を受け取れるか確認
railsのプロジェクトを作成
別のプロジェクトとしてrailsでSPAを実装
#spaディレクトリにrailsプロジェクトを作成
$rails new spa
# spaディレクトリに移動
$cd spa
# 開発サーバーの起動
$rails s
動作確認
サーバが立ち上がることを確認する
コントローラーとビューを作成
#topコントローラー(top_controller.rb)とビュー(show.html.erb)を作成
$rails g controller top show
$rails g controller top show
でtopコントローラ-とビューを作成し,ルーティングとアクション追加までしてくれます
コントローラーの確認
top_controller.rb
class TopController < ApplicationController
def show
end
end
$rails g controller top show
でshowアクションは自動で定義されるが一応のため確認.
showアクションが実行されると, app/views/top/show.html.erbを探して表示してくれる
ルーティングを定義
routes.rb
Rails.application.routes.draw do
get "", to: "top#show"
end
でtopコントローラのshowアクションが呼び出し,show.html.erbを表示できるようにした
ビューをを編集
show.html.erb
<h2>HelloWorld</h2>
HelloWorldを表示させるようにする
動作確認
#開発サーバーの起動
$rails s
show.html.erbが表示されることを確認
HelloWorldが表示されたらOK
vue.js環境構築
vueをインストール
#vue.js環境構築
$bundle exec rails webpacker:install:vue
vue.jsを利用するにあたり必要なファイルを用意してくれます。
ビューを編集
show.html.erb
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>
動作確認
$bundle exec rails s
「Hello Vue!!」と表示されていれば、環境構築は完了です。
APIを使用したSPAを作成する
axiosをインストール
#axiosをインストール
$yarn add axios
ビューを編集
app/views/top/show.html.erb
<%= javascript_pack_tag 'api' %>
<%= stylesheet_pack_tag 'api' %>
<head>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<div class="my-container">
<div class="container" id="app">
<div class="content">
<div>
<span class="index">タイトル</span><span>{{django.data.title}}</span>
</div>
<div class="blank">
<span class="index">本文</span><span>{{django.data.body}}</span>
</div>
<div>
<span class="index">名前</span><span>{{django.data.author.name}}</span>
</div>
<div class="blank">
<span class="index">メール</span><span>{{django.data.author.mail}}</span>
</div>
<select @click="search" v-model="section">
<option v-for="section in sections" :value="section">{{ section }}</option>
</select>
<br>
<button class="btn btn-primary" type="submit" @click="active">データを取得</button>
</div>
</div>
</div>
Bootstrapを使用しています.
<%= javascript_pack_tag 'api' %> <%= stylesheet_pack_tag 'api' %>
でapp/javascript/packs/api.jsを読み込んでいます.
v-model="section"
より, セレクトボックスは双方向にバインディングしています.
v-for="section in sections" :value="section"
より, sections配列に格納されている値一つ一つをvalueとして選択できるようなセレクトボックスのoptionを作っています.
@click="search"
より,クリックされた時にsearch関数が呼び出されます.
同様に, ボタンは@click="active"
より,クリックされた時にactive関数が呼び出されます.
axiosを使用
app/javascript/packs/api.jsを作成
import Vue from 'vue/dist/vue.esm'
import axios from 'axios';
document.addEventListener('DOMContentLoaded', () => {
const vm = new Vue({
el: '#app',
data() {
return {
sections:["1","2","3","4","5","6"],
section: "1",
django:null,
url :"http://localhost:8000/api/entries/1/?format=json",
lead_url:"http://localhost:8000/api/entries/",
behind_url:"/?format=json",
}
},
methods: {
active: function () {
this.url = this.lead_url + this.section + this.behind_url;
axios.get(this.url)
.then(response => {this.django = response})
},
search: function() {
this.url = this.lead_url + this.section + this.behind_url;
}
},
mounted() {
axios.get(this.url)
.then(response => {this.django = response})
},
})
})
「情報を取得する」 ボタンが押された時に実行されるactive関数では,セレクトボックスにセットされている取得したいEntryのidsection
を,HTTPメソッドを格納する変数url
に埋め込み,そのHTTPメソッドでAPIと通信を行い, データを取得しています.
axios.get(this.url)
で, HTTPメソッドを実行し, APIと通信を行う.
必要とする情報はAPIからのレスポンスの中にある.
.then(response => {this.django = response})
で, this.djangoにAPIからのレスポンスであるJSONデータを取得.
show.html.erbで{{django.data.title}}
や{{django}}
などとすることでapp.jsで宣言や取得した値を表示させることができる.
とりあえず1~6番目に作成したEntryを取得できるようにsections:["1","2","3","4","5","6"]
としました
任意で減らしたり増やしたり,取得したいEntryのidに変えてください
デザインを適用
app/assets/stylesheets/top.scss
.my-container {
width: 400px;
height: 400px;
margin: auto;
background-color: #dbdbd9;
margin-top: 200px;
select {
width: 100px;
margin: 20px;
}
.content {
display: inline-block;
margin: auto;
margin-top: 40px;
span.index {
display: inline-block;
padding: 3px;
border-radius: 5px;
background-color: #007bff;
color: white;
margin-bottom: 10px;
margin-right: 10px;
}
}
}
デザインは好みでお願いします
動作確認
$bundle exec rails s
selectボタンで取得したいEntryの番号を選択し, データを取得を押すとAPIからデータを取得することができる
SPA完成!!
GETしかできないが,他も実装予定
何も表示されない場合はdjangoのサーバが起動しているか確認したり, 検証でエラーを確認
ソース
#django_rest_frameworkディレクトリに移動
$cd django_rest_framework
#マイグレーションファイルをもとにデータベースを作成
$python manage.py migrate
#django-cors-headersをインストール
$pip install django-cors-headers
#Userを作成
$python manage.py createsuperuser
#サーバーの起動
$python manage.py runserver
#SPAディレクトリに移動
$cd SPA
#gemをインストール
$bundle install
#vueをインストール
$bundle exec rails webpacker:install:vue
#axiosをインストール
$yarn add axios
#サーバーの起動
$rails s
上記を実行してください
Discussion