RailsアプリにVue.jsを導入してみた(Vue.jsでRailsのDBを受け取る)



最近Vue.jsを勉強しはじめて、
なんとかRuby on Railsで書いた既存アプリのフロント周りをなんとかVue.jsで書き直してみたので自分用メモとして残しておきます。



#今回の目標

![vuejs.gif](https://qiita-image-store.s3.amazonaws.com/0/266199/f79018ed-bd2c-d01c-4415-64c7c5e1a5f9.gif)



画像のようにECサイト上でジャンル一覧から任意のジャンルをクリックすると、
RailsのDBから呼び出されたジャンルごとのアーティストが描画されるようにする！

#概要

どうやってこれを実装するのか
RailsのデータベースをVue.jsで受け取るにはそのまま変数で渡すことはもちろん出来ません。
なので、RailsでAPIを作ってaxiosのgetメソッドでそこを叩いてVue側で受け取ることで繋がります。


#まずVue.jsの導入
今回は既存のRailsアプリに後からVueを入れるやり方です。
Gemfileに

```ruby

gem "webpacker", github: "rails/webpacker”
```
を追記してbundle installします。


そしてターミナルで以下のコマンドを

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


##コンパイル

```terminal
$ bin/webpack
```

でコンパイルしておきましょう

コンパイルが失敗したときは

```ruby: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'
    }
  }
})

```
をapp/config/development.rbに追記してください。


ここまででapp/javascript/packsというディレクトリが出来ているはずです。
今回はhello_vue.jsというファイルにコードを追記していきます。

##Vueを読み込みましょう
application.html.erbのyieldの下に
を追加

```erb:application.html.erb 
 <%= javascript_pack_tag "hello_vue" %>
```


##APIの作成

今回hジャンルが選択されたら、そのジャンルのアーティストを配列で返すということをやりたいので、
Rails側のデータベースと連携させる必要があります。
なので

```terminal
$ bundle exec rails g controller api::genres show
```
としてまずコントローラを作りましょう

#ルーティングの追記

```ruby:routes.rb
  namespace :api do 
    resources :genres, only: %i(show)
  end
```

##API::GenresController

```ruby:api/genres_controller
class GenresController < ApplicationController
  def show
    @genre = Genre.find(params[:id])
    @artists = Artist.where(genre_id: params[:id])
  end
end
```

ちなみにジャンルは複数のアーティストを持つので、
アソシエーションはGenre has_many artistsとなってます！



また、今回json形式で渡す必要があるのでjbuilderを使います。
app/views/api/genres/show.json.jbuilderに

```ruby:show.json.jbuilder
json.genre_name @genre.genre_name
json.array do
  json.array! @genre.artists, :artist_name, :id
end
```
として、ジャンルごとのアーティスト一覧をarrayで渡しています。



##APIの確認

/api/genres/1にアクセスすると
<img width="384" alt="json.png" src="https://qiita-image-store.s3.amazonaws.com/0/266199/42368683-ef5e-7590-dd1f-bc75a6c2720f.png">
このようになっています。


ジャンルをクリックするたびにapi::genres_controllerが呼ばれて、クリックされたIDのジャンルがパラメータとして渡されています。

準備は整いました。

#Vue.jsを書いていこう！



##Vueのコード(hello_vue.js)

```javascript

import Vue from 'vue/dist/vue.esm'
import axios from 'axios'

new Vue({
  el: ".genre_vue",
  data: {
    genreInfo: {},
    artists: [],
    showModal: false,
  },
  methods: {
    setGenreInfo(id){
      axios.get(`api/genres/${id}.json`)
      .then(res => {
        this.genreInfo = res.data;
        this.artists = res.data.array;
        this.showModal = true
      });
    },
    setArtistInfo(id){
     window.location.href = `artists/${id}`;
    }
  }
});
```
RailsのAPIからデータを持ってくるために冒頭でaxiosをimportしてます。
まずdataの中でartistsを空の配列で用意します。
axiosで自作APIからgenre別のartist配列を持ってきて、this.artistsに格納します。
setArtistInfoは無理やりアーティスト詳細ページにリンクを繋げたかっただけでもっといいやり方があるはずです。。


##Railsのコード

```erb

<li v-for="artist in artists" v-on:click="setArtistInfo(artist.id)" class= "lime" v-bind:key="artist"> 
   {{ artist.artist_name }}
</li> 

```
先ほどVueの方でthis.artistsに格納された値をv-forディレクティブで回して
アーティストのアーティスト名をループさせています。



##完成です！
次は検索機能を実装していきたいと思います。
現在は検索したらページ遷移させているのVueを用いて非同期で検索結果をレンダリングさせるようにします。


#参照元
https://qiita.com/jnchito/items/30ab14ebf29b945559f6
https://qiita.com/cohki0305/items/582c0f5ed0750e60c951
https://qiita.com/cohki0305/items/a678b0b17c5b496c1de9