Rails APIモード + Vue.jsでアプリを作成する手順
やること
フロントエンドアプリケーションはVue.jsで実装し、バックエンドアプリケーションはAPIサーバーとしてのみ機能するシステムを作ること。
ルーティングはVue Routerで行い、Railsのテンプレートエンジンは使用しない。
環境構築
OS
Virtualbox + Vagrantを使います。
Downloads – Oracle VM VirtualBox
Downloads | Vagrant by HashiCorp
アプリのファイルを変更しやすくしたいので、ホストマシンで見られるように共有ファイルの設定もしました。
qiita.com
Rails
Rails6でやります。
インストールは以前やったので省略。
learning-mind.hatenablog.com
※バージョンが更新されたせいか、node.jsとかyarnのインストールでエラーになることがありましたのでご注意。
qiita.com
Rails APIモードでアプリを作成する
rails new
のオプションに--api
を加えます。
rails new sample --api
Vue.js
Vue.js 2.6.12でやります。
Vue CLIのインストール
nodeバージョン確認
$ node --version v15.3.0
node.jsがインストールされていない場合は下記ページを参照してインストールします。
prog-8.com
インストール
npm install -g @vue/cli
※Macで実行したところ失敗したので下記記事の手順で解決しました。
qiita.com
バージョン確認
$ vue -V @vue/cli 4.5.9 $ npm list -g vue /.nvm/versions/node/v15.3.0/lib └─┬ @vue/cli@4.5.9 ├─┬ vue-codemod@0.0.4 │ ├─┬ @vue/compiler-sfc@3.0.4 │ │ └── vue@3.0.4 deduped │ └── vue@3.0.4 └── vue@2.6.12
プロジェクトを作成
vue create projectname
利用するプリセット(Vue.jsのバージョン)とパッケージマネージャを訊かれます。
- プリセットは
default vue2
を選択 - パッケージマネージャは
yarn
を選択
※Macで実行したときのエラーは下記記事の手順で解決しました。
blog.kimizuka.org
アプリを起動
cd projectname npm run serve
コンソールに表示されるURLをブラウザで表示
プロジェクトをビルド
npm run build
プロジェクトルートディレクトリの配下にdist
というディレクトリが作成されます。
このディレクトリにあるファイルをHTTPサーバーに置くとかなんとか。(今回は使いません)
Vue Routerをインストール
vue add router
コーディング
Rails
render json: {[JSONオブジェクト]}
これをやればいいだけです。
モデルの作成
下記記事を参照しました。
qiita.com
rails g model post title:string rails g controller posts rails db:create rails db:migrate
コントローラにJSONを返す処理を追加
app/controllers/posts_controller.rb
class PostsController < ApplicationController def index posts = Post.all render json: posts end end
ルートを追加
config/routes.rb
Rails.application.routes.draw do resources :posts end
テスト用のレコードを用意
rails c
を実行して
irb(main):003:0> Post.create(title: "テスト用のタイトル")
APIの動作確認
X
はサーバーのIPアドレス。3000
はRailsのデフォルトのポート番号。
$ curl http://XXX.XXX.XXX.XXX:3000/posts [{"id":1,"title":"テスト用のタイトル","created_at":"2020-12-13T22:20:41.884Z","updated_at":"2020-12-13T22:20:41.884Z"}]
クロスドメイン制約対策
APIサーバー側で設定が必要です!
qiita.com
config/application.rb
config.action_dispatch.default_headers = { 'Access-Control-Allow-Credentials' => 'true', 'Access-Control-Allow-Origin' => 'http://[フロントエンドアプリケーションのIPアドレスとポート番号]', 'Access-Control-Request-Method' => '*' }
(これに気付かず、フロント側でどうにかしようとしててめちゃくちゃ時間を使いました…)
Rails側はこれでOKです。
Vue.js
ルーティング
生成されたVue Routerのファイル
src/router/index.js
import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' Vue.use(VueRouter) const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') } // ★遷移先が増える場合はここに追加していく ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes }) export default router
ルーター経由でページを遷移させる場合は、<router-link>
要素を使う。
src/App.vue
<template> <div id="app"> <div id="nav"> <router-link to="/">Home</router-link> | <router-link to="/about">About</router-link> </div> <router-view/> </div> </template>
遷移先のパスはv-bind:to=
属性でも指定できる
<router-link v-bind:to="'/about'">About</router-link>
nameプロパティでも指定でき、これを名前付きルート
という。
<router-link v-bind:to="'{ name: 'about' }">About</router-link>
ルーター経由で呼び出されたコンポーネントは、<router-view/>で確保された領域に反映される。
プログラムでルーター経由のページ移動
$router.push([パス名])
ルーター経由では以下のコンポーネントにパラメータを渡す
- ルートを追加する
- ルートパラメータを受け取る
リンク文字列を生成する
ルートを追加する 前述の★の部分に新規のルートの情報を追加します。
src/router/index.js
import Article from '../views/Article.vue' .. { path: '/article/:aid', name: 'Article', component: Article }
:aid
はプレースホルダです。
- ルートパラメータを受け取る
$route.params.aid
aid
はプレースホルダです。
今回は受け取り先として新規ビューファイルを作成します。
src/views/Article.vue
<template> <span> 記事コード:{{ $route.params.aid }} </span> </template>
- リンク文字列を生成する src/App.vue
<router-link to="/article/108">記事:No.108</router-link>
axiosのインストール
npm install axios
※CDN版を使おうとしたのですが、単一ファイルコンポーネントで使用する方法がわかりませんでした……。
axiosでAPIリクエスト
Aboutページに表示させてみます。
src/views/About.vue
<template> <div class="about"> <h1>This is an about page</h1> {{ info }} </div> </template> <script> import axios from 'axios' export default { data () { return { info: null, } }, created () { axios .get('http://[APIサーバーのIPアドレス:3000]/posts') .then(response => (this.info = response)) } } </script>
Vue.jsもこれでOK。
動作確認
rails s -b 0.0.0.0
Vue.js
npm run serve
Vue.jsアプリのIPアドレスとポート番号をブラウザに打ち込んで、「About」のリンクをクリックします。
ページ下部に先程確認したJSONのデータが表示されていれば成功です。
この後、JSONを解釈して表示すべき状態に開発を進めることができます。
参考書籍
この記事はkb Advent Calendar 2020 6日目の記事です。