mind.

学んだことの記録

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モードでアプリを作成する

qiita.com

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

note.com

JSONを返すAPIなら

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アドレス3000Railsのデフォルトのポート番号。

$ 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([パス名])

ルーター経由では以下のコンポーネントにパラメータを渡す

  1. ルートを追加する
  2. ルートパラメータを受け取る
  3. リンク文字列を生成する

  4. ルートを追加する 前述の★の部分に新規のルートの情報を追加します。
    src/router/index.js

import Article from '../views/Article.vue'
..
{
  path: '/article/:aid',
  name: 'Article',
  component: Article
}

:aidプレースホルダです。

  1. ルートパラメータを受け取る
$route.params.aid

aidプレースホルダです。
今回は受け取り先として新規ビューファイルを作成します。
src/views/Article.vue

<template>
  <span>
    記事コード:{{ $route.params.aid }}
  </span>
</template>
  1. リンク文字列を生成する src/App.vue
      <router-link to="/article/108">記事:No.108</router-link>

axiosのインストール

jp.vuejs.org

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

rails s -b 0.0.0.0

Vue.js

npm run serve

Vue.jsアプリのIPアドレスとポート番号をブラウザに打ち込んで、「About」のリンクをクリックします。
ページ下部に先程確認したJSONのデータが表示されていれば成功です。
この後、JSONを解釈して表示すべき状態に開発を進めることができます。

参考書籍

www.amazon.co.jp

この記事はkb Advent Calendar 2020 6日目の記事です。

adventar.org