【動画付き】Rails 5.1で作るVue.jsアプリケーション ～Herokuデプロイからシステムテストまで～

## はじめに

Rails 5.1ではJavaScript/index.html.erb周りのサポートが大きく改善されました。
これにより、Vue.jsやReactといったモダンなJSフレームワークをRails内で非常に扱いやすくなっています。

僕も実際に試してみましたが、本当にびっくりするぐらい簡単にVue.jsやReactを動かすことができました。
そこでこの記事ではRails 5.1とVue.jsを組み合わせたサンプルアプリケーションの作成方法をチュートリアル形式で、できるだけ詳しく説明します。

また、ローカルで動かしておしまい、ではなく、Herokuにデプロイしたり、テストコードを書いたりするところまでカバーします。

この記事自体は長いですが、実際に手を動かすと（スムーズに進んだ場合）30分以内で終わらせることができるはずです！

## 今回作成するサンプルアプリケーション

今回は以下のリンク先にあるVue.jsのアプリケーションをRails上で作成します。

http://jsfiddle.net/yyx990803/23qze30k/

このサンプルアプリケーションではテーブルのソートや、データの絞り込みがVue.jsの機能を使って実装されています。

![647Lxuyt8h.gif](https://qiita-image-store.s3.amazonaws.com/0/7465/adf6a5b7-973b-6fa3-6032-1b7e256558cb.gif "647Lxuyt8h.gif")

## この記事の解説動画

この記事の内容はYouTubeでも解説しています。
実際にコードを書いたり、画面を動かしたりする様子が動画で確認できるので、さらに内容が理解しやすくなるはずです。

[https://www.youtube.com/watch?v=ycOeM2umXkY![Screen Shot 2017-02-27 at 10.12.55.png](https://qiita-image-store.s3.amazonaws.com/0/7465/59c67fb5-aa2f-83fe-69ac-9ad5982a2838.png "Screen Shot 2017-02-27 at 10.12.55.png")](https://www.youtube.com/watch?v=ycOeM2umXkY)

ちなみに、動画の長さは約40分です。
1.5倍速～2倍速ぐらいで再生すると、サクサクっと視聴できると思います。

## この記事で作成したコード

この記事で作成したコードはGitHubにアップしてあります。
コミットログを追いかけていくと、どこで何が変わったのか把握しやすくなると思います。
こちらも参考にしてください。

https://github.com/JunichiIto/rails-vue-sandbox

それでは以下が本編です！

## Rubyバージョンの確認

この記事ではRuby 2.4.0を使います。

```
$ ruby -v
ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-darwin16]
```

ですが、おそらくRuby 2.2.2以上なら動作するはずです。

## Railsバージョンの確認

この記事ではRails 5.1.0.beta1を使います。
（なので、正式リリース時には多少仕様が変わる可能性があります）

```
$ rails -v
Rails 5.1.0.beta1
```

なお、`gem install rails -v 5.1.0.beta1`でインストールできない場合は、以下のコマンドを試してみてください。

```
$ ruby -rbundler/inline -e "gemfile(true) do; source 'https://rubygems.org/'; gem 'rails', '5.1.0.beta1'; end"
```

参考：[Installing pre release gems is giving conflicting dependency errors · Issue \#1653 · rubygems/rubygems](https://github.com/rubygems/rubygems/issues/1653)

## 新規Railsアプリを作成する

Rails 5.1でVue.jsを使う場合、3通りの方法があります。

1. `rails new`に`--webpack=vue`オプションを付けて、プロジェクトの作成時にVue.jsもインストールする
2. `rails new`に`--webpack`オプションを付ける。その後、Vue.jsをインストールする
3. 普通に`rails new`して、それからWebpackerとVue.jsをインストールする

一番手軽なのは1の方法ですが、このチュートリアルではWebpackerやVue.jsのインストール時にどこが変わるのか確認するため、あえて3の方法で進めます。

というわけで、以下のコマンドを実行してRailsアプリを作成してください。

```
$ rails new rails-vue-sandbox
```

### Commitログ

[Initial commit · JunichiIto/rails\-vue\-sandbox@281aa22](https://github.com/JunichiIto/rails-vue-sandbox/commit/281aa2257acd0bab05ceb7e3623f89d179b2fd5e)

## Webpacker gemのインストール

続いて、Webpacker gemをインストールします。
Gemfileに以下の行を追加し、`bundle install`してください。

```ruby:Gemfile
gem 'webpacker', github: 'rails/webpacker'
```

それから`bin/rails webpacker:install`というコマンドを実行するのですが、その前にまず、Yarnがインストールされていることを確認してください。

```
$ yarn -v
yarn install v0.20.3
[1/4] 🔍  Resolving packages...
success Already up-to-date.
✨  Done in 0.42s.
```

インストールされていなければ、以下のページを参考にしてインストールしておきましょう。

[Installation \| Yarn](https://yarnpkg.com/lang/en/docs/install/#mac-tab)

Yarnのインストールが済んだら、`bin/rails webpacker:install`を実行します。

```
$ bin/rails webpacker:install
```

これでWebpack関連のファイルや設定が追加されます。

新規追加

- `app/javascript/packs/application.js`
- `bin/webpack`
- `bin/webpack-dev-server`
- `bin/webpack-watcher`
- `config/webpack/development.js`
- `config/webpack/production.js`
- `config/webpack/shared.js`
- `yarn.lock`

変更

- `.gitignore`
- `config/environments/development.rb`
- `config/environments/production.rb`
- `package.json`

### Commitログ

[Install webpacker · JunichiIto/rails\-vue\-sandbox@b4b6a58](https://github.com/JunichiIto/rails-vue-sandbox/commit/b4b6a585ae0e98a4a57ba713b1c96f0abf302893)

## Vue.jsのインストール

今度はVue.jsのインストールです。
Webpackerをインストールしていれば、コマンド一発でVue.jsがインストールできます。

```
$ rails webpacker:install:vue
```

これでVue.js用のファイルや設定が追加されます。

新規追加

- `app/javascript/packs/app.vue`


```html:app/javascript/packs/app.vue
<template>
  <div id="app">
    Hello Vue!
  </div>
</template>
```

- `app/javascript/packs/hello_vue.js`

```javascript:app/javascript/packs/hello_vue.js
// Run this example by adding <%= javascript_pack_tag 'hello_vue' %> to the head of your layout file,
// like app/views/layouts/application.html.erb.
// All it does is render <div>Hello Vue</div> at the bottom of the page.

import Vue from 'vue'
import App from './app.vue'

document.body.appendChild(document.createElement('hello'))

new Vue({
  el: 'hello',
  template: '<App/>',
  components: { App }
})
```

変更

- `config/webpack/shared.js`
- `package.json`
- `yarn.lock`

## hello_vue.jsを表示する画面を作成する

次に、`hello_vue.js`を表示する画面を作成します。
まず、コントローラを作成します。

```
$ rails g controller Home index
```

コントローラの中身はそのままでOKです。

```rb:app/controllers/home_controller.rb
class HomeController < ApplicationController
  def index
  end
end
```

Viewは空っぽにしておきます。

```erb:app/views/home/index.html.erb

```

`app/views/layouts/application.html.erb`には`<%= javascript_pack_tag 'hello_vue' %>`を追加します。

```diff:app/views/layouts/application.html.erb
 <!DOCTYPE html>
 <html>
   <head>
     <title>RailsVueSandbox</title>
     <%= csrf_meta_tags %>
 
     <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
     <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
   </head>
 
   <body>
     <%= yield %>
+    <%= javascript_pack_tag 'hello_vue' %>
   </body>
 </html>
```

`routes.rb`では、`home#index`をrootページに指定します。

```rb:config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
end
```

### JSのコンパイル

次に、Vue.js関連のJavaScriptをコンパイルします。
JSのコンパイルには`bin/webpack`を使います。
ただし、2017年2月27日時点では、このコマンドを実行するとエラーが出ます。

```
$ bin/webpack
(node:41610) DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see https://github.com/webpack/loader-utils/issues/56
parseQuery() will be replaced with getOptions() in the next major version of loader-utils.
Hash: c4d67f31e483f6e6e58e
Version: webpack 2.2.1
Time: 752ms
             Asset     Size  Chunks             Chunk Names
      hello_vue.js   232 kB       0  [emitted]  hello_vue
    application.js  3.37 kB       1  [emitted]  application
  hello_vue.js.map   285 kB       0  [emitted]  hello_vue
application.js.map  3.33 kB       1  [emitted]  application
   [0] ./app/javascript/packs/app.vue 2.05 kB {0} [built] [failed] [1 error]
   [1] ./~/vue/dist/vue.common.js 226 kB {0} [built]
   [2] (webpack)/buildin/global.js 509 bytes {0} [built]
   [3] ./app/javascript/packs/application.js 489 bytes {1} [built]
   [4] ./app/javascript/packs/hello_vue.js 415 bytes {0} [built]

ERROR in ./app/javascript/packs/app.vue
Module build failed: Error: 

Vue packages version mismatch:

- vue@2.1.10
- vue-template-compiler@2.2.1

This may cause things to work incorrectly. Make sure to use the same version for both.
If you are using vue-loader@>=10.0, simply update vue-template-compiler.
If you are using vue-loader@<10.0 or vueify, re-installing vue-loader/vueify should bump vue-template-compiler to the latest.

    at Object.<anonymous> (/Users/jit/dev/sandbox/rails-vue-sandbox-2/node_modules/vue-template-compiler/index.js:8:9)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/jit/dev/sandbox/rails-vue-sandbox-2/node_modules/vue-loader/lib/parser.js:1:78)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/jit/dev/sandbox/rails-vue-sandbox-2/node_modules/vue-loader/lib/loader.js:2:13)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
    at Module.require (module.js:498:17)
    at require (internal/module.js:20:19)
    at Object.<anonymous> (/Users/jit/dev/sandbox/rails-vue-sandbox-2/node_modules/vue-loader/index.js:1:80)
    at Module._compile (module.js:571:32)
    at Object.Module._extensions..js (module.js:580:10)
    at Module.load (module.js:488:32)
    at tryModuleLoad (module.js:447:12)
    at Function.Module._load (module.js:439:3)
```

このエラーを解消するために、`yarn upgrade vue`でVue.jsのバージョンを上げてください。

```
$ yarn upgrade vue
yarn upgrade v0.20.3
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning "url-loader@0.5.8" has unmet peer dependency "file-loader@*".
[4/4] 📃  Building fresh packages...
success Saved 1 new dependency.
└─ vue@2.2.1
✨  Done in 4.36s.
```

こうすると、`bin/webpack`の実行に成功するはずです。

```
$ bin/webpack
bin/webpack
(node:60134) DeprecationWarning: loaderUtils.parseQuery() received a non-string value which can be problematic, see https://github.com/webpack/loader-utils/issues/56
parseQuery() will be replaced with getOptions() in the next major version of loader-utils.
Hash: 5324517c32736f3529f8
Version: webpack 2.2.1
Time: 1043ms
             Asset     Size  Chunks             Chunk Names
      hello_vue.js   249 kB       0  [emitted]  hello_vue
    application.js  3.37 kB       1  [emitted]  application
  hello_vue.js.map   309 kB       0  [emitted]  hello_vue
application.js.map  3.33 kB       1  [emitted]  application
   [0] ./app/javascript/packs/app.vue 1.21 kB {0} [built]
   [1] ./~/vue/dist/vue.common.js 242 kB {0} [built]
   [2] ./~/vue-loader/lib/component-normalizer.js 1.15 kB {0} [built]
   [3] ./~/vue-loader/lib/template-compiler.js?{"id":"data-v-20bbc081"}!./~/vue-loader/lib/selector.js?type=template&index=0!./app/javascript/packs/app.vue 407 bytes {0} [built]
   [4] (webpack)/buildin/global.js 509 bytes {0} [built]
   [5] ./app/javascript/packs/application.js 489 bytes {1} [built]
   [6] ./app/javascript/packs/hello_vue.js 415 bytes {0} [built]
```

### hello_vue.jsの動作確認

それではrails serverを起動しましょう。

```
$ rails s
```

http://localhost:3000 にアクセスして、次のような画面が表示されればOKです。
（Rails上でVue.jsが実行できました。おめでとうございます！:tada:）

![Screen Shot 2017-02-27 at 9.07.19.png](https://qiita-image-store.s3.amazonaws.com/0/7465/f7f22078-a828-f2f9-88e5-d6c9839ec3c6.png "Screen Shot 2017-02-27 at 9.07.19.png")

### Commitログ

[Create home\#index · JunichiIto/rails\-vue\-sandbox@470fc67](https://github.com/JunichiIto/rails-vue-sandbox/commit/470fc67f8e5293770576b1dc0ae1cc54dc532bfb)

## Vue.jsサンプルアプリケーションの作成

さて、Vue.jsが動作する環境が整ったので、サンプルアプリケーションを作成に移りましょう。
今回はこちらのページにあるコードを使わせてもらいます。

http://jsfiddle.net/yyx990803/23qze30k/

View、JS、CSSをそれぞれ次のように書き換えてください。

```html:app/views/home/index.html.erb
<!-- component template -->
<script type="text/x-template" id="grid-template">
  <table>
    <thead>
    <tr>
      <th v-for="key in columns"
          @click="sortBy(key)"
          :class="{ active: sortKey == key }">
        {{ key | capitalize }}
        <span class="arrow" :class="sortOrders[key] > 0 ? 'asc' : 'dsc'">
          </span>
      </th>
    </tr>
    </thead>
    <tbody>
    <tr v-for="entry in filteredData">
      <td v-for="key in columns">
        {{entry[key]}}
      </td>
    </tr>
    </tbody>
  </table>
</script>

<!-- demo root element -->
<div id="demo">
  <form id="search">
    Search <input name="query" v-model="searchQuery">
  </form>
  <demo-grid
  :data="gridData"
  :columns="gridColumns"
  :filter-key="searchQuery">
  </demo-grid>
</div>
```

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

// register the grid component
Vue.component('demo-grid', {
  template: '#grid-template',
  replace: true,
  props: {
    data: Array,
    columns: Array,
    filterKey: String
  },
  data: function () {
    var sortOrders = {}
    this.columns.forEach(function (key) {
      sortOrders[key] = 1
    })
    return {
      sortKey: '',
      sortOrders: sortOrders
    }
  },
  computed: {
    filteredData: function () {
      var sortKey = this.sortKey
      var filterKey = this.filterKey && this.filterKey.toLowerCase()
      var order = this.sortOrders[sortKey] || 1
      var data = this.data
      if (filterKey) {
        data = data.filter(function (row) {
          return Object.keys(row).some(function (key) {
            return String(row[key]).toLowerCase().indexOf(filterKey) > -1
          })
        })
      }
      if (sortKey) {
        data = data.slice().sort(function (a, b) {
          a = a[sortKey]
          b = b[sortKey]
          return (a === b ? 0 : a > b ? 1 : -1) * order
        })
      }
      return data
    }
  },
  filters: {
    capitalize: function (str) {
      return str.charAt(0).toUpperCase() + str.slice(1)
    }
  },
  methods: {
    sortBy: function (key) {
      this.sortKey = key
      this.sortOrders[key] = this.sortOrders[key] * -1
    }
  }
})

// bootstrap the demo
var demo = new Vue({
  el: '#demo',
  data: {
    searchQuery: '',
    gridColumns: ['name', 'power'],
    gridData: [
      { name: 'Chuck Norris', power: Infinity },
      { name: 'Bruce Lee', power: 9000 },
      { name: 'Jackie Chan', power: 7000 },
      { name: 'Jet Li', power: 8000 }
    ]
  }
})
```

```css:app/assets/stylesheets/home.scss
body {
  font-family: Helvetica Neue, Arial, sans-serif;
  font-size: 14px;
  color: #444;
}

table {
  border: 2px solid #42b983;
  border-radius: 3px;
  background-color: #fff;
}

th {
  background-color: #42b983;
  color: rgba(255,255,255,0.66);
  cursor: pointer;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

td {
  background-color: #f9f9f9;
}

th, td {
  min-width: 120px;
  padding: 10px 20px;
}

th.active {
  color: #fff;
}

th.active .arrow {
  opacity: 1;
}

.arrow {
  display: inline-block;
  vertical-align: middle;
  width: 0;
  height: 0;
  margin-left: 5px;
  opacity: 0.66;
}

.arrow.asc {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-bottom: 4px solid #fff;
}

.arrow.dsc {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 4px solid #fff;
}
```

これらのコードを組み込んだら、JSをコンパイルします。

```
$ bin/webpack
```

そしてブラウザをリロードすると、jsfiddleで表示されていた画面と同じ画面が表示されるはずです。
ソートや検索も動作することを確認しておきましょう。

![647Lxuyt8h.gif](https://qiita-image-store.s3.amazonaws.com/0/7465/adf6a5b7-973b-6fa3-6032-1b7e256558cb.gif "647Lxuyt8h.gif")

### Commitログ

[Create sample app · JunichiIto/rails\-vue\-sandbox@a46704f](https://github.com/JunichiIto/rails-vue-sandbox/commit/a46704fff619a78f4f7194f9c1fa354b54f441a5)

## Herokuへのデプロイ

ローカルで動かしておしまい、ではなく、本番環境でも使えるようにしましょう。
今回はHerokuにデプロイしてみます。
（HerokuのアカウントやCLIツールは事前にセットアップしておいてください）

### コードの変更

まず、Gemfileを変更します。変更箇所は以下の3点です。

- Rubyのバージョンを指定する
- pg gemをインストールする
- sqlite3 gemを`:development, :test`グループに移動させる

```diff:Gemfile
 source 'https://rubygems.org'
 
+ruby '2.4.0'
+
 git_source(:github) do |repo_name|
   repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
   "https://github.com/#{repo_name}.git"
@@ -8,8 +10,7 @@ end
 
 # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
 gem 'rails', '~> 5.1.0.beta1'
-# Use sqlite3 as the database for Active Record
-gem 'sqlite3'
+gem 'pg'
 # Use Puma as the app server
 gem 'puma', '~> 3.7'
 # Use SCSS for stylesheets
@@ -35,6 +36,7 @@ gem 'jbuilder', '~> 2.5'
 # gem 'capistrano-rails', group: :development
 
 group :development, :test do
+  gem 'sqlite3'
   # Call 'byebug' anywhere in the code to stop execution and get a debugger console
   gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
   # Adds support for Capybara system testing and selenium driver
```

Gemfileを変更したら`bundle install`を実行します。

続いて、プロジェクトのルートディレクトリに`Procfile`を作成します。

```text:Procfile
web: bundle exec puma -p $PORT
```

### Commitログ

[Setup for Heroku · JunichiIto/rails\-vue\-sandbox@8c1827d](https://github.com/JunichiIto/rails-vue-sandbox/commit/8c1827d90a6edb0a0a30b238028cd9f69ee3b8c6)

### Herokuインスタンスの作成とデプロイ

Herokuへのデプロイは次のようにコマンドを入力していってください。

```
# インスタンスの作成
$ heroku create

# add-onの追加
$ heroku addons:create heroku-postgresql:hobby-dev

# ビルドパックの追加
$ heroku buildpacks:add --index 1 heroku/nodejs
$ heroku buildpacks:add --index 2 heroku/ruby

# デプロイとマイグレーション実行
$ git push heroku master
$ heroku run rake db:migrate

# Heroku上のアプリケーションを開く
$ heroku open
```

通常のデプロイと変わっている点はビルドパックを追加するところです。
これを追加しないと、デプロイ時にエラーが発生します。

参考：[Introducing Webpacker – Statuscode – Medium](https://medium.com/statuscode/introducing-webpacker-7136d66cddfb#.pxuboxy0l)

Heroku上のアプリケーションを開いたときに、ローカルと同じように動作すればOKです！

![JjdabqGftj.gif](https://qiita-image-store.s3.amazonaws.com/0/7465/ece6de28-9599-5ce9-9f59-aa8ad98c935c.gif "JjdabqGftj.gif")

## webpack-dev-serverを有効にする

さて、今のままだと、Vue.js用のJSを変更するたびに毎回`bin/webpack`を実行しなければいけません。
これはちょっと面倒なので、webpack-dev-serverという機能を利用して、JSを変更したらすぐに変更が反映されるようにしましょう。

まず、ルートディレクトリに`Procfile.dev`というファイルを作成します。

```Procfile.dev
web: bundle exec rails s
# watcher: ./bin/webpack-watcher
hot: ./bin/webpack-dev-server
```

それから、`bin`ディレクトリの下に`server`という名前のファイルを作成します。

```text:bin/server
#!/bin/bash -i
bundle install
bundle exec foreman start -f Procfile.dev
```

`server`は実行可能なファイルにしておきます。

```
$ chmod 777 bin/server
```

また、`server`では`foreman`を使うので、Gemfileに追加して`bundle install`します。

```diff:Gemfile
 group :development do
   # ...
+  gem 'foreman'
 end
```

最後に、`config/environments/development.rb`にある、`config.x.webpacker[:dev_server_host] = "http://localhost:8080"`のコメントを外します。

```diff:config/environments/development.rb
 Rails.application.configure do
   # Make javascript_pack_tag load assets from webpack-dev-server.
-  # config.x.webpacker[:dev_server_host] = "http://localhost:8080"
+  config.x.webpacker[:dev_server_host] = "http://localhost:8080"
```

`rails s`でサーバーを起動していたら停止し、`bin/server`でサーバーを起動してください。
サーバーが起動したら http://localhost:5000/ にアクセスします。

こうすると、`hello_vue.js`への変更が、即座に画面に反映されるようになります。

![YLZV9SLrYZ.gif](https://qiita-image-store.s3.amazonaws.com/0/7465/fff73ca1-82a1-6b30-54fa-060fbfd1bcdf.gif "YLZV9SLrYZ.gif")

### Commitログ

[Setup for webpack\-dev\-server · JunichiIto/rails\-vue\-sandbox@07d8a79](https://github.com/JunichiIto/rails-vue-sandbox/commit/07d8a7969b6cc6b30c596486028a8abaa22e8874)

## Vue.js用のシステムテストを書く

最後に、この画面のテストコードも書いておきましょう。
Rails 5.1ではSystemTestCaseという新しいテストケースクラスが導入されました。
これを使うと、JavaScriptを利用する画面のテストが書けます。

SystemTestCaseではChromeDriverというドライバを使います。
これは事前にセットアップが必要です。
以下の記事を参考にしてセットアップしてください。

[Rails 5\.1のSystemTestCaseを試してみた \- Qiita](http://qiita.com/jnchito/items/4d01f2faa1deee36bd27)

ChromeDriverをセットアップしたら、テストコードを作成します。
今回は`test/system/home_test.rb`というファイルを作成します。

```ruby:test/system/home_test.rb
require "application_system_test_case"

class HomeTest < ApplicationSystemTestCase
  test "visiting the index" do
    # トップページを開く
    visit root_path

    # 4人とも表示される
    assert_text 'Chuck Norris'
    assert_text 'Bruce Lee'
    assert_text 'Jackie Chan'
    assert_text 'Jet Li'

    # "J"でフィルタリングする（2人表示）
    fill_in 'query', with: 'J'
    assert_no_text 'Chuck Norris'
    assert_no_text 'Bruce Lee'
    assert_text 'Jackie Chan'
    assert_text 'Jet Li'

    # "Jet"でフィルタリングする（1人だけ表示）
    fill_in 'query', with: 'Jet'
    assert_no_text 'Chuck Norris'
    assert_no_text 'Bruce Lee'
    assert_no_text 'Jackie Chan'
    assert_text 'Jet Li'
  end
end
```

なお、コントローラのテストは使わないので中身を消しておきます。

```ruby:test/controllers/home_controller_test.rb
require 'test_helper'

class HomeControllerTest < ActionDispatch::IntegrationTest
  # 削除
end
```

テストコードが書けたら、テストを実行します。

```
$ rake
Run options: --seed 19056

# Running:

Puma starting in single mode...
* Version 3.7.1 (ruby 2.4.0-p0), codename: Snowy Sagebrush
* Min threads: 0, max threads: 1
* Environment: test
* Listening on tcp://0.0.0.0:64816
Use Ctrl-C to stop
.

Finished in 3.184606s, 0.3140 runs/s, 0.0000 assertions/s.

1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
```

このようにすると、モダンなJavaScriptフレームワークを使っている場合でもちゃんとテストを書くことができます。

### Commitログ

[Test for home\#index · JunichiIto/rails\-vue\-sandbox@caebff1](https://github.com/JunichiIto/rails-vue-sandbox/commit/caebff19a15d3d957adebcbfce93eb548dfbc17d)

## 応用：Vue.jsではなくReactやAngularを使う

今回はVue.jsを使いましたが、ReactやAngular（+TypeScript）を使う場合も基本的な流れは同じです。

`rails webpacker:install:vue`の代わりに、`rails webpacker:install:react`や`rails webpacker:install:angular`を実行するとReactやAngular用のセットアップが完了します。

詳しくはWebpacker gemのREADMEをご覧ください。

https://github.com/rails/webpacker

## 参考：おおまかなディレクトリ＆ファイル構成

今回のVue.jsアプリケーションに関連しそうなディレクトリとファイルだけを、独断でピックアップしてtree表示してみました。
各ファイルはこんな感じで配置されています。

```
.
├── app
│   └── javascript
│       └── packs
│           ├── app.vue
│           ├── application.js
│           └── hello_vue.js
├── bin
│   ├── webpack
│   ├── webpack-dev-server
│   ├── webpack-watcher
│   └── yarn
├── config
│   └── webpack
│       ├── development.js
│       ├── production.js
│       └── shared.js
├── node_modules
│   └── vue
├── package.json
├── public
│   └── packs
│       ├── application.js
│       ├── application.js.map
│       ├── hello_vue.js
│       └── hello_vue.js.map
└── yarn.lock
```

## まとめ

というわけで、この記事ではRails 5.1でVue.jsのサンプルアプリケーションを作成する手順を説明しました。

これまではモダンなJavaScriptフレームワークに対して「いっぱいツールがあって、スタートラインに立つまでが大変」という印象を持っていました。
しかし、Rails 5.1を使うとあっという間にVue.jsやReactの開発環境を構築することができました。
これはとてもすごいことだと思います。

もちろん、ここで作成したのはHello, worldレベルのサンプルアプリケーションの作成です。
実務で使うためにはもっといろんな知識が必要になるはずです。
とはいえ、「とりあえず動かして試せる環境」があるのとないのでは大違いです。

動かせる環境があれば、「何をどうすればどう変わるのか」が理解しやすくなるので、漠然と技術記事を眺めるよりもぐんと学習効率がアップすると思います。

この記事を参考にして、みなさんもぜひ手元でモダンなJSフレームワーク環境を構築してみてください！

### あわせて読みたい

僕が書いたRails 5.1関連のQiita記事です。
こちらもあわせてどうぞ。

- [Rails 5\.1の変更点まとめ \- Qiita](http://qiita.com/jnchito/items/b0b47ecfc33de4f9b72f) [![](http://b.st-hatena.com/entry/image/http://qiita.com/jnchito/items/b0b47ecfc33de4f9b72f)](http://b.hatena.ne.jp/entry/http://qiita.com/jnchito/items/b0b47ecfc33de4f9b72f)
- [Rails 5\.1のSystemTestCaseを試してみた \- Qiita](http://qiita.com/jnchito/items/4d01f2faa1deee36bd27) [![](http://b.st-hatena.com/entry/image/http://qiita.com/jnchito/items/4d01f2faa1deee36bd27)](http://b.hatena.ne.jp/entry/http://qiita.com/jnchito/items/4d01f2faa1deee36bd27)

### Special thanks

Rails 5.1で導入されたJSの新機能については、以下の記事を参考にさせてもらいました。
どうもありがとうございました。

- [Railsが5\.1になることでフロントエンドの開発が本当に楽しくなりました \- チラシ裏日記上等！！新館](http://www.chirashiura.com/entry/2017/02/26/013532)
- [Introducing Webpacker – Statuscode – Medium](https://medium.com/statuscode/introducing-webpacker-7136d66cddfb#.4nejv7uxh)
- [Rails 5\.1でreact環境を作ってみた \- Qiita](http://qiita.com/kikunantoka/items/54f1859496003b1b1aff)