Rails 5.1 + Vue.js の使い方

# はじめに

今更ですが、Rails5.1からwebpackがサポートされてReact, Angular, Vueが簡単にインストールできるようになったので、それぞれ試してみたいと思い、まずはvue.jsを動かしてみました。

# 実行環境

OS : MacOS X
Ruby 2.4.2
Rails 5.1.4
webpack 3.5.5
vue 2.5.9
yarn 1.3.2

### 捕捉
事前にyarn（javascriptのパッケージ管理）をインストールしてることが前提となります。
Mac OS x の方はbrewコマンドで一発でインストール可能です。
yarnのバージョンが古いとインストールで失敗します。

```bash
$ brew upgrade yarn
# または
$ brew upgrade yarn
```

# プロジェクト作成

```bash
$ mkdir vue-sample && cd vue-sample
$ rails new vue-sample --webpack=vue
```

### 捕捉
`--webpack=vue` がvueの指定になります。
angularやreactを使用したい場合はvueの箇所を変更すれば対応可能です。

# 開発サーバ設定

Railsでは通常`rails server`コマンドを使用しますが、`webpack-dev-server`コマンドでwebpack用のビルドサーバも起動しないといけないので、両方を一度に起動できる`foreman`を使用します。

まずはGemfileに追記します。

```diff:Gemfile

group :development do
  ...
+ gem 'foreman'
end
```

追記が終わったら`bundle install`を実行してください。

設定用のProcfileをアプリケーションルートに作成し、実行内容を記載します。

```:Procfile
rails: bundle exec rails server
webpack: ./bin/webpack-dev-server
```

実行します。

```bash
$ foreman start
```
`http://localhost:5000` にアクセスするとrailsの画面が表示されます。


# サンプルファイル実行

`app/javascript/`の下に以下のサンプルファイルがありますので表示させます。
（hello worldを表示させます。）

```
.
├── app
│   └── javascript`
│       ├── packs
│       │   ├── hello_vue.js
│       │   ├── application.js
│       └── app.vue
...
```

## HellowWorldを表示させるページの作成


まずはページの作成

```
$ rails g controller about index
```

サーバを起動（`foreman start`）した状態で`http://localhost:5000/about/index`にアクセスできることを確認してください。

続いてvue関連のファイルを読み込めるように`app/view/layout/application.html.erb`に追記します。


```diff:application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>VueSample</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
+   <%= javascript_pack_tag 'hello_vue' %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>
```

これで`http://localhost:5000/about/index`にアクセスしてみて以下のようなページが表示されればOKです。

![スクリーンショット 2017-12-08 10.37.59.png](https://qiita-image-store.s3.amazonaws.com/0/29570/8a658834-611a-a492-1073-bc2970ce7a72.png)


あとは`app/javascript/app.vue`, `app/javascript/packs/hello_vue.js`を変更することで表示の調整が可能です。

# Vueを編集してみる

今回は既存のhtml/erbテンプレートの要素をターゲットにして、コンポーネントを使いつつ、バインディングの機能を使用したいので、`app/javascript/packs/hello_vue.js`に記載されているコメントを参考にサンプルコードを変更します。

まずは、バインディング用のhtmlを追記します。

```diff:app/views/about/index.html.erb
<h1>About#index</h1>
<p>Find me in app/views/about/index.html.erb</p>

+ <div id='hello'>
+ {{message}}
+ <app></app>
+ </div>
```

次に`app/javascript/packs/hello_vue.js`の修正を行います。
基本的にはコメントアウトしたりコメントを解除するだけです。

```diff:app/javascript/packs/hello_vue.js

-import Vue from 'vue'
-import App from '../app.vue'
-
-document.addEventListener('DOMContentLoaded', () => {
-  document.body.appendChild(document.createElement('hello'))
-  const app = new Vue(App).$mount('hello')
-
-  console.log(app)
-})
+//import Vue from 'vue'
+//import App from '../app.vue'
+//
+//document.addEventListener('DOMContentLoaded', () => {
+//  document.body.appendChild(document.createElement('hello'))
+//  const app = new Vue(App).$mount('hello')
+//
+//  console.log(app)
+//})

-// import Vue from 'vue/dist/vue.esm'
-// import App from './app.vue'
-//
-// document.addEventListener('DOMContentLoaded', () => {
-//   const app = new Vue({
-//     el: '#hello',
-//     data: {
-//       message: "Can you say hello?"
-//     },
-//     components: { App }
-//   })
-// })
+ import Vue from 'vue/dist/vue.esm'
+ import App from '../app.vue'
+
+ document.addEventListener('DOMContentLoaded', () => {
+   const app = new Vue({
+     el: '#hello',
+     data: {
+       message: "Can you say hello?"
+     },
+     components: { App }
+   })
+ })
```
**注意点としてサンプルコードのコメントは ` import App from './app.vue' `となっていますがドットが一つ足りないので ` import App from '../app.vue' `としてください。**

整理すると以下のようになります。

```js:app/javascript/packs/hello_vue.js
import Vue from 'vue/dist/vue.esm'
import App from '../app.vue'
document.addEventListener('DOMContentLoaded', () => {
  const app = new Vue({
    el: '#hello',
    data: {
      message: "Can you say hello?"
    },
    components: { App }
  })
})
```

これで以下のように表示されればOKです！

![スクリーンショット 2017-12-08 16.23.56.png](https://qiita-image-store.s3.amazonaws.com/0/29570/d2b39d2a-90ea-6470-1d84-8a561471de0e.png)