RailsとVue.jsを使った簡単な項目追加機能を作ってみる

仕事でRailsとVueを利用することが出てきたので、
テキストで簡単な項目追加(タグ追加のようなイメージ)の手順を記載してみる。

###環境
Mac　High Sierra
ruby 2.5.1
Rails 5.2.1

#実装したこと
・index画面にタグ一覧を表示させる(削除リンクを設定)
・タグの追加をindex画面上で実施(画面遷移しない)
・タグ追加処理をVueで実施
＊バリデーションやエラーチェックなどはあまり気にせず作成

#1.rails new
rails newに--webpack=vueオプションを付けて、プロジェクトの作成時にVue.jsもインストールさせる

```ruby
rails new tag_sample --webpack=vue
```

#2.モデル作成、マイグレーション

```ruby
cd tag_sample
rails g model tag name:string
rake db:create
rake db:migrate
```

#3.コントローラー作成

```ruby
rails g controller tags
```

#4.ルーティング設定
config/routes.rb

```ruby
  resources :tags
```

#5.コントローラー設定

```ruby:app/controller/tags_controller.rb
class TagsController < ApplicationController
  def index
    @tags = Tag.all
  end

  def create
    tag_params.each do |tag_name|
      tag_data = Tag.create(name: tag_name)
      tag_data.save!
    end
    redirect_to  tags_path
  end

  def destroy
    @tag = Tag.find(params[:id])
    @tag.destroy
    redirect_to tags_url
  end

  private

  def tag_params
    params.require(:tags)
  end
end
```

#6.ビューの設定

```ruby:app/views/tags/index.html.erb
<h1>Tags</h1>

<table>
  <thead>
  <tr>
    <th>id</th>
    <th>Name</th>
    <th colspan="3"></th>
  </tr>
  </thead>

  <tbody>
  <% @tags.each do |tag| %>
    <tr>
      <td><%= tag.id %></td>
      <td><%= tag.name %></td>
      <td><%= link_to 'Destroy', tag, method: :delete, data: { confirm: 'Are you sure?' } %></td>
    </tr>
  <% end %>
  </tbody>
</table>

<%= form_with model: @tag,
              local: true do |f| %>
<div id = "tag-app">
  <%= javascript_pack_tag 'tag' %>
</div>

<%= f.submit %>
<% end %>
```

#7.Vueの処理設定
###構成
app/javascript配下に以下を設定

```
javascript
 |_packs
　 　|_tag.js
 |_components
　 　|_tag_component.vue
```

```javascript:packs/tag.js
import Vue from 'vue';
import TagComponent from '../components/tag_component.vue';

new Vue({
    el: '#tag-app',
    components: { TagComponent },
    template: '<TagComponent/>',
});
```
 

```vue:components/tag_component.vue
<template>
  <div id="tag-app">
        <input type="text"
            name="Tag"
            v-model="newTag">
        <button type="button"
            v-on:click="setTag">追加</button>
        <p v-if="tags.length === 0">
                <input type="hidden"
                   name="tags[]"
                   :value="tag">
        </p>
        <ul v-else>
            <li v-for="(tag, index) in tags">{{tag}}
                <input type="hidden"
                   name="tags[]"
                   :value="tag">
                <button type="button"
                   @click="delTag(tag)"
                   >×</button>
            </li>
        </ul>
    </div>
</template>

<script>
    export default {
        data () {
            return {
                tags: [] ,
                newTag: null,
            }
        },
        methods: {
            setTag: function () {
                var tag = this.newTag;
                if (! tag) {
                  alert('タグを入力して！');
                  return;
                }
                this.tags.push(tag);
                this.newTag = '';
            },
            delTag: function(tag) {
                this.tags.splice(this.tags.indexOf(tag), 1);
            },
        }
     }
</script>
 ```
#8.webpackのBuildをする

```console
bin/webpack-dev-server 
```

#9.ローカルサーバー起動

```console
rails s
```

###9-1. http://localhost:3000/tags  にアクセス
<img width="350" alt="スクリーンショット 2018-10-08 2.42.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/248644/7ef32052-ce02-e4b1-c8df-a5368e184eda.png">


###9-2.タグを追加
<img width="350" alt="スクリーンショット 2018-10-08 2.43.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/248644/c735241d-b4a9-6d21-e8d3-45c3882ac52d.png">

###9-3.saveしてDBに反映
<img width="350" alt="スクリーンショット 2018-10-08 2.43.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/248644/cf3b2fe3-0c65-331c-9778-a454e270a86b.png">

とりあえず、想定した動作を作ることができた。
テストした後にキャプチャしているので、idが増えた状態になっている...のは、あまり気にせず。

#consoleで以下のエラーが出た場合の対応
```console
[Vue warn]: You are using the runtime-only build of Vue where the template compiler is not available. Either pre-compile the templates into render functions, or use the compiler-included build.
```

config/webpack/development.rbを以下に設定(configファイルにaliasを追加)

```ruby:config/webpack/development.rb
process.env.NODE_ENV = process.env.NODE_ENV || 'development'

const environment = require('./environment')

module.exports = Object.assign({}, environment.toWebpackConfig(), {
    resolve: {
        alias: {
            'vue$': 'vue/dist/vue.esm.js'
        }
    }
})
```