Vue.js チュートリアル for Rails エンジニア(Vue2 version)

# はじめに
この記事は、普段 rails を使用して開発を行なっているエンジニアが、 Vue.js を触り始めようとする時に見て役に立ったら嬉しいものです。

今回は Vue2 での開発を想定したものになります。 Vue3 での開発に関して知りたい方は下記の記事をご覧ください。
[Vue.js チュートリアル for Rails エンジニア(Vue3 version)](https://qiita.com/t0yohei/items/cd11b15642fbb26f71e2)

# 対象読者

- Rails に関しての知識がある程度ある方(Rails チュートリアルをやっていれば OK)
- Vue.js に関しての知識がある程度ある方(なんらかのチュートリアルなどをやっていれば OK。)
- Rails + Vue のアプリケーションをどうやって開発すればいいかを知りたい方

# チュートリアルの内容
チュートリアルは、以下の2本立てで行うことで、 Vue.js に触れたことがない Rails エンジニアでも理解しやすい形にしています。すでに Vue.js に触れたことがある場合は、1を飛ばして、2から始めるのが良いかと思います。

1. 簡単な Vue.js アプリケーションの開発
2. [Webpacker](https://github.com/rails/webpacker) を使用した簡単な Rails + Vue.js アプリケーションの開発

# 1. 簡単な Vue.js アプリケーションの開発
を書こうと思ったら、すでにめちゃくちゃいいチュートリアル記事が既にあったので、そちらのリンクを掲載させていただきます。(タイトル詐欺)
[Vue.js を vue-cli を使ってシンプルにはじめてみる](https://qiita.com/567000/items/dde495d6a8ad1c25fa43)

# 2. Webpacker を使用した簡単な Rails + Vue.js アプリケーションの開発
1 がだいたい終わって、 Vue.js のことをだいたい理解していることが前提です。

作成予定の画面は ↓ にあるような、簡単なテーブル構造を持つ画面になります。

<div>
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/5996c21b-ad88-e217-9968-1496df8b7b58.png" width="300">
  <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/147cca55-d74c-2ed8-0111-97162a618fc4.png" width="300">
</div>

[サンプルコードはこちら](https://github.com/t0yohei/rails-vue-app) で公開しています。

# 使用するバージョン
- ruby: 2.6.2
- rails: 5.2.3
- webpacker: 4.0.7
- yarn: 1.16.0

# 環境構築
環境構築には、 `homebrew` , `rbenv` を使用します。インストールがまだな方は、各自インストールをお願いします。

## アプリケーションを作成するディレクトリを作成
はじめに、これからアプリケーションを実装していくディレクトリを `rails-vue-app` という名前で作成します。今回はこの `rails-vue-app` がアプリケーションの名前になります。

```shell
$ mkdir rails-vue-app
$ cd rails-vue-app
```

## rbenv を使用して Ruby 2.6.2 をインストール

Ruby 2.6.2 をインストールします。

```shell
$ brew update && brew install ruby-build // または brew update && brew upgrade ruby-build
$ rbenv install 2.6.2
$ rbenv local 2.6.2
$ rbenv rehash
$ ruby -v 
ruby 2.6.2p47 (2019-03-13 revision 67232) [x86_64-darwin18]
```

## yarn のインストール
yarn をインストールします。
今回は 1.16.0 を前提に進めていきますが、 1.16.0 以上であれば基本問題ないはずです。

```shell
$ brew install yarn // または brew upgrade yarn
$ yarn -v
1.16.0
```

## Vue.js devtools のインストール
インストールがまだな場合は、下記のページを参考にインストールしておきましょう。
[Vue.js Devtoolsの導入方法と機能まとめ。Vue.jsを用いた開発を効率化させよう！](https://qiita.com/hashimoto-1202/items/c81f5d4c271eef16d957)


## プロジェクトの作成

下記コマンドを実行して、プロジェクトを作成します。

```shell
$ bundle init
$ echo 'gem "rails", "~> 5.2.3"' >> Gemfile
$ bundle install --path vendor/bundle
$ bundle exec rails new . --webpack=vue --skip-turbolinks --skip-coffee
```

※ `--skip-turbolinks --skip-coffee` のオプションをつけて、今回は不要となるものを削ぎ落としています。 [^1]

実行結果のログを眺めていると、 gem のインストールの後に、 `rails  webpacker:install` から始まる webpacker 関連のインストールが行われていることがわかります。

```shell
rails  webpacker:install
RAILS_ENV=development environment is not defined in config/webpacker.yml, falling back to production environment
```

webpacker のインストールが完了すると、普段の rails プロジェクトでは見られない、 `app/javascript` というディレクトリが、自動で生成されているかと思います。

```shell
$ cd rails-vue-app/app/javascript
$ ls
  app.vue packs
```

※ 今回の実装では、新規に Rails + Vue.js のプロジェクトを作ることを想定していますが、もちろん既存の Rails プロジェクトに途中から Vue.js を導入することもできます。[^2]


それでは、これから rails アプリケーションの中身の実装を進めていこうと思います。

# アプリケーションの実装
## 一番シンプルな実装
まずは、 rails 上で vue.js を動かす一番シンプルな実装をしていきます。
`cd` コマンドなどで先ほど作成したディレクトリに移動し、まずはコントローラーを作成します。

```shell
$ bundle exec rails g controller HelloVue index --no-helper --no-assets
```

※ 今回は、ヘルパーやアセットファイルなど不要なものを生成しないオプションを指定しています。 [^3]

一旦サーバーを起動して、画面が表示するかみて見ましょう。

```shell
$ bundle exec rails s
```

http://localhost:3000/hello_vue/index にアクセスして、下記のページが表示されると ok です。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/39905448-f90b-1608-24c4-1ec8ed0f4ec1.png' width=300>

### javascript_pack_tag の設定
`javascript_pack_tag` で `app/javascript/packs` 配下にあるファイルを読み込むことができます。 (この辺は [webpackerの仕様](https://github.com/rails/webpacker#usage)で決まっています)
今回は、読み込む対象として `hello_vue.js` を指定してみます。 `hello_vue.js` は webpacker のインストール時に自動生成されているファイルです。

```diff:app/views/hello_vue/index.html.erb
  <h1>HelloVue#index</h1>
  <p>Find me in app/views/hello_vue/index.html.erb</p>
+ <%= javascript_pack_tag 'hello_vue.js' %>
```

`hello_vue.js` の中身は、下記のような感じになっており、同じく初期作成された `app.vue` ファイルを描画するようになっています。

```app/javascript/packs/hello_vue.js
import Vue from 'vue'
import App from '../app.vue'

document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    render: h => h(App)
  }).$mount()
  document.body.appendChild(app.$el)

  console.log(app)
})
```

```app/javascript/app.vue
  <div id="app">
    <p>{{ message }}</p>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      message: "Hello Vue!"
    }
  }
}
</script>

<style scoped>
p {
  font-size: 2em;
  text-align: center;
}
</style>
```

これらのファイルがどう言う役割をしているのかが曖昧な場合は、もう一度 [簡単な Vue.js アプリケーションの開発](https://qiita.com/drafts/d516fefaaad69b4022ec/edit#1-%E7%B0%A1%E5%8D%98%E3%81%AA-vuejs-%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AE%E9%96%8B%E7%99%BA) の項を見てみましょう。

### webpacker を使用した webpack のビルド
下記のコマンドを実行することで、 `app/javascript` 配下の js ファイルをビルドすることができます。

```shell
$ bin/webpack
```

このコマンドは、内部的には下記のコマンドを実行しているのにほぼ等しいらしいです。(知らなかった)

```shell
$ ./node_modules/.bin/webpack --config config/webpack/development.js
```
※ [Webpacker使うなら最低限これだけは知っておいてほしいこと](https://qiita.com/chimame/items/8d3d6f4afea675cffa7d) から抜粋させてもらいました。

再度 http://localhost:3000/hello_vue/index にアクセスしてみると、下記のような画面になっているかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/500d7ad1-bb04-0f2f-9ffa-586bba94003a.png)


環境構築で、 `Vue.js devtools` のインストールが完了している場合、 chrome の拡張機能の部分に、 `V` のマークが色付きで出てきているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/c6050a3a-c2c3-de96-a5f2-f39beaeff64a.png)

この時点で、一番の基本となる rails + Vue.js のアプリケーション実装が完了しました。:tada:

### webpack の自動ビルド
先ほどは、 `bin/webpack` のビルドを行いましたが、これでは js ファイルを変更するたびに再度コマンドを叩いてビルドをする必要があります。
流石にそれは面倒なので、開発中は `bin/webpack` の代わりに下記コマンドを実行して、ファイルを保存するたびに自動ビルドが走るようにしておくといいでしょう。

```shell
$ bin/webpack-dev-server
```

### Vue.js devtools
せっかくなので `Vue.js devtools` の使い方をここで確認しておきます。
使い方は簡単で、 chrome の developer ツールを開いて、 Vue のタブを選択するだけです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/485111cb-2753-d85d-869e-dded0adcd0ad.png" width='500'>

Vue のタブを選択し、コンポーネントを選択してみると、内部の data などを確認することができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/b775c70b-46b0-38c5-2031-6550677a605d.png" width='500'>

※ 上手く表示できない場合は、 Vue2 の `Vue.js devtools` が off になっており、 Vue3 のものだけが on になっているかを確認したり、 `Developer tools` を一度閉じて開き直したりしてみてください。 


# 実践的な実装
先ほど実装はただ単に、作成した vue ファイルの描画を行っただけで、 controller などからのデータの受け渡しを行なっていませんでした。そこで、ここからはその点を深掘っていきます。

webpacker を使用した、 rails + vue のアプリケーションを作成する際、データの渡し方には色々あるらしいですが、今回は2通りのデータの受け渡し方でサンプルアプリケーションを作っていきます(個人的にはこの2つの渡し方は、データフローがわかりやすい)。

- HTML のデータ属性に値を設定して渡す方法
- API を使用して渡す方法

前者の方法については、下記の記事を参考にさせていただきました。
[メンテ不能になったフロントエンド環境を立て直す話](https://engineer.crowdworks.jp/entry/2019/05/28/114806)

## HTML のデータ属性に値を設定して渡す方法
まずはページを表示するためのコントローラーを、 `HomeController` という名前で作成します。 

```shell
$ bundle exec rails g controller Home index --no-helper --no-assets
```

次にコントローラー内部の実装を進めていきます。 `index` メソッドのインスタンス変数として、 `title` `description` そして Hash 形式の `contents` を用意します。

```diff:app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
+   @title = 'Home#index'
+   @description = 'トップページ'
+   @contents = get_contents
  end
+
+ private
+
+ def get_contents
+   {
+     outer_links: [
+       {
+         name: 'Qiitaページ',
+         text: 'Qiita',
+         url: 'https://qiita.com/t0yohei/items/d516fefaaad69b4022ec'
+       },
+       {
+         name: 'ソースコード',
+         text: 'GitHub',
+         url: 'https://github.com/t0yohei/rails-vue-app'
+       }
+     ],
+   }
+ end
end
```

続いて `view` の実装です。ここでポイントとなるのが、 rails の `content_tag` ヘルパーを利用して、 `div` タグの `data` 属性に vue 側に受け渡したいデータ設定している点です。 vue に受け渡すデータは `json` 形式に変換しておきます。

```diff:app/views/home/index.html.erb
- <h1>Home#index</h1>
- <p>Find me in app/views/home/index.html.erb</p>
+ <%= javascript_pack_tag 'home/index.js' %>
+ <%= content_tag :div,
+   id: "homeIndex",
+   data: {
+     title: @title,
+     description: @description,
+     contents: @contents
+   }.to_json do %>
+ <% end %>
```

生成される html は下記画像のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/aeca759b-991d-1a2b-0ebb-c48cfb425384.png)

※ `data` 属性に設定した情報は、 developer tool などを使うことで閲覧することができるので、 API 同様にユーザーのプライペート情報など、秘匿情報は公開しないようにして注意してください。

## data 属性に設定した値を読み込む js ファイルを作成

`home/index.js` では、 `home/Index` というコンポーネントを render することを想定して実装を進めていきます。 render 関数の第二引数に、先ほど取得した Object のデータを設定します。

```diff:app/javascript/packs/home/index.js
 import Vue from "vue";
+import Index from "../../components/home/Index.vue";

 document.addEventListener("DOMContentLoaded", () => {
   const node = document.getElementById("homeIndex");
   const props = JSON.parse(node.getAttribute("data"));
+  const app = new Vue({
+    render: h => h(Index, { props })
+  }).$mount();
+  document.body.appendChild(app.$el);
-  console.log(props);
 });
```

render 対象の、 `home/Index` コンポーネントでは、受け取る props を定義しておきます。これで `home/index.js` からデータを受け取って、コンポーネント内で参照することができます。

```app/javascript/components/home/Index.vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
    <table class="contents-table">
      <tr>
        <th>名前</th>
        <th>リンク</th>
      </tr>
      <tr v-for="outer_link in contents.outer_links" v-bind:key="outer_link.name">
        <td>{{ outer_link.name }}</td>
        <td>
          <a v-bind:href="outer_link.url">{{ outer_link.text }}</a>
        </td>
      </tr>
    </table>
  </div>
</template>

<style scoped>
.contents-table {
  border: 1px solid gray;
  margin: 10px;
}
.contents-table th,
.contents-table td {
  border: 1px solid gray;
}
</style>

<script>
export default {
  props: {
    title: {
      type: String,
      default: () => ""
    },
    description: {
      type: String,
      default: () => ""
    },
    contents: {
      type: Object,
      default: () => {}
    }
  }
};
</script>

```

### ページの表示
`app/javascript/packs` 配下に追加した js ファイルを読み込ませるためには、 `webpack-dev-server` の再起動が必要です。 `webpack-dev-server` を実行中の場合は一度止めて、再度下記コマンドを実行しましょう。

```shell
$ bin/webpack-dev-server
```

http://localhost:3000/home/index にアクセスした時に、下記のようなページが表示されていると成功です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/f5da4a61-b39c-30df-b328-954f3f718799.png" width='500'>


## 実装のリファクタリング
とりあえず表示させることを優先で、 `Index.vue` に全てを書いていたので、簡単にコンポーネントの分割をしていきます。ざっとこんな感じのイメージで分割していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/d11f7c27-bd8c-21e1-e8a4-95035d6be25b.png)


### HeaderView.vue の作成

```app/javascript/components/HeaderView.vue
<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ description }}</p>
  </div>
</template>
<script>
export default {
  props: {
    title: {
      type: String,
      default: () => ""
    },
    description: {
      type: String,
      default: () => ""
    }
  }
};
</script>
<style scoped></style>
```

### Contents.vue の作成

```app/javascript/components/home/Contents.vue
<template>
  <div>
    <table class="contents-table">
      <tr>
        <th>名前</th>
        <th>リンク</th>
      </tr>
      <tr v-for="outer_link in contents.outer_links" v-bind:key="outer_link.name">
        <td>{{ outer_link.name }}</td>
        <td>
          <a v-bind:href="outer_link.url">{{ outer_link.text }}</a>
        </td>
      </tr>
    </table>
  </div>
</template>

<script>
export default {
  props: {
    contents: {
      type: Object,
      default: () => {}
    }
  }
};
</script>

<style scoped>
.contents-table {
  border: 1px solid gray;
  margin: 10px;
}
.contents-table th,
.contents-table td {
  border: 1px solid gray;
}
</style>
```

### Index.vue の修正

```diff:app/javascript/components/home/Index.vue
 <template>
   <div>
-    <h1>{{ title }}</h1>
-    <p>{{ description }}</p>
-    <table class="contents-table">
-      <tr>
-        <th>名前</th>
-        <th>リンク</th>
-      </tr>
-      <tr v-for="outer_link in contents.outer_links" v-bind:key="outer_link.name">
-        <td>{{ outer_link.name }}</td>
-        <td>
-          <a v-bind:href="outer_link.url">{{ outer_link.text }}</a>
-        </td>
-      </tr>
-    </table>
+    <header-view v-bind:title="title" v-bind:description="description"></header-view>
+    <contents v-bind:contents="contents"></contents>
   </div>
 </template>

-<style scoped>
-.contents-table {
-  border: 1px solid gray;
-  margin: 10px;
-}
-.contents-table th,
-.contents-table td {
-  border: 1px solid gray;
-}
-</style>
+<style scoped></style>

 <script>
+import HeaderView from "../HeaderView.vue";
+import Contents from "./Contents.vue";
+
 export default {
+  components: {
+    "header-view": HeaderView,
+    contents: Contents
+  },
  props: {
    title: {
      type: String,
      default: () => ""
    },
    description: {
      type: String,
      default: () => ""
    },
    contents: {
      type: Object,
      default: () => {}
    }
  }
};
</script>
```

だいぶスッキリしましたね。リファクタリングは一旦こんな感じで終わりましょうか。
念の為、再度 http://localhost:3000/home/index にアクセスして、画面がちゃんと表示されることを確認しておきましょう。

## API を使用して渡す方法での実装
次に、API を使用して渡す方法での実装を進めていきましょう。
今回は特に理由もないんですが、整数リテラルの分類表を作成してみます。
手順としては、 

- APIを叩いて取得したデータを受け取るコンポーネントの実装
- APIエンドポイントの実装
- コンポーネントから API を叩いてデータを取得
- 取得したデータをコンポーネント内で描画

という順番で進めていきます。

### APIを叩いて取得したデータを受け取るコンポーネントの実装

まずはページを表示するためのコントローラーを作成します。

```shell
$ bundle exec rails g controller IntegerLiteralDescriptions index --no-helper --no-assets
```

#### コントローラーの実装
今回は何もしないです。

#### View の実装
`javascript_pack_tag` を設定します。

```diff:app/views/integer_literal_descriptions/index.html.erb
- <h1>IntegerLiteralDescriptions#index</h1>
- <p>Find me in app/views/integer_literal_descriptions/index.html.erb</p>
+ <%= javascript_pack_tag 'integerLiteralDescriptions/index.js' %>
```

#### 表示するコンポーネントの実装

#### `integerLiteralDescriptions/index.js` の実装

```app/javascript/packs/integerLiteralDescriptions/index.js
import Vue from "vue";
import Index from "../../components/integerLiteralDescriptions/Index.vue";

document.addEventListener("DOMContentLoaded", () => {
  const app = new Vue({
    render: h => h(Index)
  }).$mount();
  document.body.appendChild(app.$el);
});
```

#### コンポーネントの実装
```app/javascript/components/integerLiteralDescriptions/Index.vue
<template>
  <div>
    <header-view v-bind:title="title" v-bind:description="description"></header-view>
    <contents v-bind:contents="contents"></contents>
  </div>
</template>

<script>
import HeaderView from "../HeaderView.vue";
import Contents from "./Contents.vue";

export default {
  components: {
    "header-view": HeaderView,
    contents: Contents
  },
  data: function() {
    return {
      title: "title",
      description: "description",
      contents: []
    };
  }
};
</script>

<style scoped>
</style>
```

```app/javascript/components/integerLiteralDescriptions/Contents.vue
<template>
  <div>
    <table class="contents">
      <tr>
        <th>名前</th>
        <th>英語訳</th>
        <th>表記例</th>
        <th>用途</th>
      </tr>
      <tr v-for="content in contents" v-bind:key="content.name">
        <td>{{ content.name }}</td>
        <td>{{ content.english }}</td>
        <td>{{ content.sample }}</td>
        <td>{{ content.usage }}</td>
      </tr>
    </table>
  </div>
</template>
<style scoped>
.contents {
  border: 1px solid gray;
}
.contents th,
.contents td {
  border: 1px solid gray;
}
</style>
<script>
export default {
  props: {
    contents: Array
  }
};
</script>
```

再び `bin/webpack-dev-server` を実行し直し、 http://localhost:3000/integer_literal_descriptions/index にアクセスすると、下記画像のようなページが表示されるかと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/735f6b90-212f-8fce-826d-028e5f2ac159.png" width='400'>

これで API を叩いて取得したデータを受け取り、表示するためのコンポーネントが完成しました。

次は、先ほど作成したコンポーネントに、データを渡す処理を実装していこうと思います。

### APIエンドポイントの実装

```shell
$ bundle exec rails g controller api/v1/integer_literal_descriptions index --no-helper --no-assets --no-view-specs
```

#### コントローラーの実装

```diff:app/controllers/api/v1/integer_literal_descriptions_controller.rb
 class Api::V1::IntegerLiteralDescriptionsController < ApplicationController
   def index
+    title = 'IntegerLiteralDescriptions#index'
+    description = '整数リテラルの分類表'
+    contents = get_integer_literals
+    result_values = {
+      title: title,
+      description: description,
+      contents: contents
+    }
+    render json: result_values
   end
-end
+
+  private
+
+  def get_integer_literals
+    [
+      {
+        name: '10進数',
+        english: 'decimal',
+        sample: '42',
+        usage: '数値'
+      },
+      {
+        name: '2進数',
+        english: 'binary digits',
+        sample: '0b0001',
+        usage: 'ビット演算など'
+      },
+      {
+        name: '8進数',
+        english: 'octal',
+        sample: '0o777',
+        usage: 'ファイルのパーミッションなど'
+      },
+      {
+        name: '16進数',
+        english: 'hexadecimal, hex',
+        sample: '0xEEFF',
+        usage: '文字のコードポイント、RGB値など'
+      }
+    ]
+  end
+end
```

#### アクセスの確認
この状態で、 http://localhost:3000/api/v1/integer_literal_descriptions/index にアクセスしてみると、下記のような画面が表示されるはずです。
　
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/6841f34d-1bb5-b843-b729-20ac2eefb0fd.png)

一旦これで、 API のエンドポイントが完成しました。

### コンポーネントから API を叩いてデータを取得
コンポーネントと API の Ajax 通信は [axios](https://github.com/axios/axios) というライブラリを使用して行います。[^4]
まずは `axios` をインストールします。

```shell
$ yarn add --dev axios
```

install に成功していると、 `package.json` `axios` の項目が追記されているはずです。

```diff:package.json
   "devDependencies": {
+    "axios": "^0.19.0",
     "webpack-dev-server": "^3.7.2"
   }
```

次に `integerLiteralDescriptions/Index.vue` を書き換えて、 axios でのデータ取得を実装します。

```diff:app/javascript/components/integerLiteralDescriptions/Index.vue
 import Contents from "./Contents.vue";
+import Axios from "axios";

 export default {
   components: {
     "header-view": HeaderView,
     contents: Contents
   },
   data: function() {
     return {
       title: "title",
       description: "description",
       contents: []
     };
+  },
+
+  created: function() {
+    this.updateContents();
+  },
+
+  methods: {
+    updateContents() {
+      Axios.get("/api/v1/integer_literal_descriptions/index.json").then(
+        response => {
+          const responseData = response.data;
+          console.log(responseData);
+        }
+      );
+    }
   }
```

`created` で vue コンポーネントが作成されたタイミングで `axios` によるデータ取得を走らせるようにしています。
`console.log` で取得したデータを表示するようにしているので、 http://localhost:3000/integer_literal_descriptions/index を見てみましょう。
↓のようなログが出て、データ取得ができているはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/53efcc47-4697-e491-bb3c-fbe07cc7ba6a.png)

### Tips: JS のデバッグ
ご存知な方も多いと思いますが、 JS では debugger を仕込むことで、デバッグ実行が可能になります。
[debugger ステートメント | MDN](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/debugger)

具体的には下記のように仕込むことができます。

```diff:app/javascript/components/integerLiteralDescriptions/Index.vue
   Axios.get("/api/v1/integer_literal_descriptions/index.json").then(
     response => {
       const responseData = response.data;
-      console.log(responseData);
+      debugger;
     }
   );
```

開発者ツールを開きながら、再度先ほどの http://localhost:3000/integer_literal_descriptions/index にアクセスしてみると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/d3426fcc-cd8d-15bf-0adb-96d78219f9ce.png)

`debugger` を仕込んだ部分で処理が止まり、 `Console` からその時点の各種データを覗くことができます。(↑画像の場合、画像下部で `responseData` の値を確認しています。)

### 取得したデータをコンポーネント内で描画
先ほど `axios` で取得したデータを、画面に反映させます。
今回の場合、下記の部分を書き換えるだけです。

```diff:app/javascript/components/integerLiteralDescriptions/Index.vue
   Axios.get("/api/v1/integer_literal_descriptions/index.json").then(
     response => {
       const responseData = response.data;
-      console.log(responseData);
+      this.title = responseData.title;
+      this.description = responseData.description;
+      this.contents = responseData.contents;
     }
   );
```

http://localhost:3000/integer_literal_descriptions/index にアクセスしてみると、整数リテラル分類表が出てくるはず！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/8c33664a-db72-e8b3-c45d-dc742731fbdb.png" width="500">

### 整数リテラル分類表
JS では 0 で始まる数値の直後に `b, o, x` をつけると、それぞれ2進数、8進数、16進数が表現できるみたいですね。 `b, o, x` は 英語訳を見てみると、それぞれ binary digits, octal, hex となっており、なるほどなーとなるんじゃないでしょうか。今回整数リテラル分類表をサンプルに組み込んだ理由は特にないです。気まぐれです。

### リンクボタンを追加
せっかくなので、 `http://localhost:3000/home/index` から `http://localhost:3000/integer_literal_descriptions/index` に飛べるように、リンクボタンを追加しておきましょう。

```diff:app/controllers/home_controller.rb
           url: 'https://github.com/t0yohei/rails-vue-app'
         }
       ],
+      inner_links: [{
+        label: '整数リテラル分類表',
+        url: url_for(action: 'index', controller: 'integer_literal_descriptions')
+      }]
     }
```

```diff:app/javascript/components/home/Contents.vue
...
         </td>
       </tr>
     </table>
+    <div v-for="inner_link in contents.inner_links" v-bind:key="inner_link.label">
+      <button v-on:click="changeLocation(inner_link.url)" class="btn-push">{{ inner_link.label }}</button>
+    </div>
   </div>
 </template>
 <style scoped>
...
+.btn-push {
+  margin: 10px;
+  max-width: 180px;
+  text-align: left;
+  background-color: rgb(24, 174, 238);
+  font-size: 14px;
+  color: #fff;
+  text-decoration: none;
+  font-weight: bold;
+  padding: 10px 24px;
+  border-radius: 4px;
+  border-bottom: 4px solid rgb(24, 174, 238);
+}
+.btn-push:active {
+  transform: translateY(4px);
+  border-bottom: none;
+}
 </style>
 <script>
 export default {
   props: {
     contents: {
       type: Object,
       default: () => {}
     }
+  },
+  methods: {
+    changeLocation(url) {
+      window.location.href = url;
+    }
   }
 };
 </script>
```

http://localhost:3000/home/index を開いて、こんな感じのボタンができていたらokです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/152779/38a85c48-683d-feaa-5090-830fff894028.png" width=400>

### 最後に
今回のチュートリアルはここで終了です。 会社の人が Vue.js を触り始める時に使ってもらえたらなーと思いこのチュートリアルの作成を計画したのですが、せっかくなので Qiita に投稿してみることにしました。どこかのエンジニアの役に立つと幸いです。


[^1]: 今回の実装では [CoffeeScript](http://coffeescript.org/) と [turbolinks](https://github.com/turbolinks/turbolinks) のセットアップを省いています。既存の rails プロジェクトで Vue.js を使用する場合は、 turbolinks と[戦う必要がありそう](https://tech.misoca.jp/entry/2018/02/02/110000)です。

[^2]: もし既存の rails プロジェクトに途中から導入する場合は、右記をご参考ください。[rails/webpacker#installation](https://github.com/rails/webpacker#installation)

[^3]: オプションの詳細は、 [こちら](http://railsdoc.com/rails#%E3%82%B3%E3%83%B3%E3%83%88%E3%83%AD%E3%83%BC%E3%83%A9%E3%81%AE%E7%94%9F%E6%88%90(rails%20generate%20controller)) や `rails g controller -h` コマンドで確認できます。

[^4]: [axios を利用した API の使用](https://jp.vuejs.org/v2/cookbook/using-axios-to-consume-apis.html)