LoginSignup
16
15

More than 3 years have passed since last update.

RailsにWebpack+Vue.jsを、出来るだけ気楽に導入してみる

Last updated at Posted at 2019-08-01

はじめに

Vue.jsにはHTML/CSS/Javascriptを単一のファイルにまとめることのできる、コンポーネント機能があります。
しかし、コンポーネントを使用するためにはトランスパイラが必要となり、Rails標準のアセットパイプラインでは処理できません。
そのため、RailsにWebpackを導入することになります。
Webpackの導入方法は多くありますが、極力Railsに手を入れない方法で導入してみようと思います。

動作環境

動作に必要なパッケージ(カッコ内は確認したバージョン)
これらのインストールについては本記事では割愛します。
(確認日:2019/7/17)

  • Linux (Debian Stretch)
  • Ruby (2.5.5)
  • npm (6.4.1)
  • Bundler (2.0.1)
  • MariaDB (mysql Ver 15.1 Distrib 10.1.38-MariaDB)(Railsが対応していれば別のDBでも可)

この記事でgemやnpmから導入するパッケージの動作確認バージョンは以下になります。

  • Ruby on Rails (5.2.3)
  • Webpack (4.35.0)
  • Vue.js (2.6.10)
  • axios (0.19.0)

参考資料

基本的に以下の2つの記事をまとめた形になります。

この他、基礎から学ぶ Vue.js(所謂猫本)を参考にしています。

開発方針

  • Sprocketsは残したままWebpackを導入する
  • Railsプロジェクトに/frontendディレクトリを作成し、Webpackを導入する
  • Webpackは/app/assets/javascript/webpack.jsにスクリプトを出力する。
  • Webpackで処理したファイルをSprocketsで再度処理する。そういった不合理さは気にしない人向け。
  • jQueryはwebpackで管理せず、Rails側で用意するかCDNを用いるかのどちらかとする(本記事ではjQueryを使用していない)

/frontend以下のディレクトリ構成

/frontend
|- config
|  |- production
|  |  |- webpack.config.js
|  |- development
|     |- webpack.config.js
|- node_modules
|- src
|  |- javascripts
|     |- components
|     |  |- vuesample.vue
|     |  |- vuesampleItem.vue
|     |- entry.js
|- package.json

Railsのインストール

project_nameというRailsプロジェクトを作成するとします。

Shell
mkdir project_name
cd project_name
bundle init

bundle initでGemfileを作成します。
今回は5.2系最新版をインストールします。
今後Rails6以降を使いたい場合はバージョンを変更します。

Gemfile
gem "rails" , "~> 5.2"

vender/bundle以下にRailsをインストールします。

Shell
bundle install --path=vendor/bundle

rails newします。Turbolinksは無効にします。
DBはMySQL(MariaDB)を指定していますが、任意のDBで問題ありません。
-Bオプションを指定しているため、bundleは行われません。
実行すると、上書きするかを聞かれるので上書きします。

Shell
bundle exec rails new . -B -d mysql --skip-turbolinks

Gemfileを編集してpryをインストールします。

Gemfile
group :development do
  # ↓追加
  gem 'pry-byebug'
end

bundle updateでインストールします。

Webpackを導入する

Webpackなどパッケージのインストール

Railsのルートディレクトリに/frontendディレクトリを作成し、Webpackをインストールします。

Shell
mkdir frontend
cd frontend

package.jsonを作成します。

Shell
npm init

色々質問されますが、デフォルト値で構いません。
質問が終わったら、必要なパッケージをインストールします。

Shell
npm i --save vue webpack webpack-cli vue-loader vue-template-compiler css-loader style-loader babel-loader @babel/core @babel/preset-env sass-loader node-sass

webpackの設定ファイルを作成

/frontend/config/development/webpack.config.js
/frontend/config/production/webpack.config.js
を作成します。

mkdir config
mkdir config/development
mkdir config/production
touch config/development/webpack.config.js
touch config/production/webpack.config.js

今回はWebpack4用の設定ファイルを作ります。
Webpackの設定ファイルはバージョンにより異なるため注意が必要です。

Webpackの出力先を/app/assets/javascriptsにするためには絶対パスでの指定が必要です。
/home/vagrant/projects/project_name/app/assets/javascriptsの部分は開発環境のパスに書き換える必要があります。

devtool: 'inline-source-map'を指定することで、ブラウザからのデバッグが可能になります。

/frontend/config/development/webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  devtool: 'inline-source-map', //デバッグに必要
  mode: 'development', // Webpack4では必須
  entry: {
    webpack: './src/javascripts/entry.js' //Keyがファイル名になる
  },
  output: {
    // /app/assets以下に出力(フルパスで記述)
    // ここを書き換え
    path: '/home/vagrant/projects/project_name/app/assets/javascripts',
    filename: '[name].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['vue-style-loader', 'css-loader'] // css-loader -> vue-style-loaderの順で通していく
      },
      {
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          {
            loader: 'sass-loader',
          },
        ],
      }
    ]
  },
  resolve: {
    // import './foo.vue' の代わりに import './foo' と書けるようになる(拡張子省略)
    extensions: ['.js', '.vue'],
    alias: {
      // vue-template-compilerに読ませてコンパイルするために必要
      vue$: 'vue/dist/vue.esm.js',
    },
  },
  plugins: [
    new VueLoaderPlugin()
  ],
  // jQueryはRails側で用意するか、CDNを使用
  // (CoffeeScriptからjQueryを呼び出す可能性を想定)
  // 記事内ではjQueryを使用していない。読み込まなくてもエラーにならない。
  externals: {
    jquery: 'jQuery'
  }
}

production環境用のconfigも同様に作ります。

  • mode: 'production'を指定してコードを圧縮すること
  • devtool: 'inline-source-map'を削除していること
  • production環境でのアセットプリコンパイルを通すため、ES6以降のJavaScriptをES5に変換するように指定すること

が、developmentとの違いになります。

/frontend/config/production/webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  mode: 'production', // Webpack4では必須
  entry: {
    webpack: './src/javascripts/entry.js' //Keyがファイル名になる
  },
  output: {
    // /app/assets以下に出力(フルパスで記述)
    // ここを書き換え
    path: '/home/vagrant/projects/project_name/app/assets/javascripts',
    filename: '[name].js'
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader',
        options: {
          presets: [
            // ES5に変換するように指定
            "@babel/preset-env"
          ]
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      {
        test: /\.css$/,
        use: ['vue-style-loader', 'css-loader'] // css-loader -> vue-style-loaderの順で通していく
      },
      {
        test: /\.scss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          {
            loader: 'sass-loader',
          },
        ],
      }
    ]
  },
  resolve: {
    // import './foo.vue' の代わりに import './foo' と書けるようになる(拡張子省略)
    extensions: ['.js', '.vue'],
    alias: {
      // vue-template-compilerに読ませてコンパイルするために必要
      vue$: 'vue/dist/vue.esm.js',
    },
  },
  plugins: [
    new VueLoaderPlugin()
  ],
  // jQueryはRails側で用意するか、CDNを使用
  externals: {
    jquery: 'jQuery'
  }
}

package.jsonを編集して、npm runから実行できるようにします。

/frontend/package.json
  "scripts": {                                                                     
    "test": "echo \"Error: no test specified\" && exit 1",
    // ↓下の3つを追加                         
    "release": "webpack --config config/production/webpack.config.js",             
    "build": "webpack --config config/development/webpack.config.js",              
    "watch": "webpack --watch --config config/development/webpack.config.js"       
  },                                                                               

npm run buildでdevelopment環境、npm run releaseでproduction環境での処理が行われます。

Railsに組み込む

Railsで動作確認をするため、Railsのルートディレクトリに移動して適当なコントローラを作ります。

Shell
cd ..
bundle exec rails g controller samples
/app/controllers/pages_controller.rb
def index
end
/config/routes.rb
Rails.application.routes.draw do
  # ↓追加
  resources :samples
end
/app/views/samples/index.html.erb
<div id="app">
  <p>{{name}}</p>
</div>
/frontend/src/javascripts/entry.js
import Vue from 'vue';

document.addEventListener("DOMContentLoaded", function(event) {
  new Vue({
    el: '#app',
    data: {
      name: 'aaa'
    }
  });
});

npm run buildnpm run releaseを実行して、
/app/assets/webpack.jsを生成します。

DBのパスワードの設定

このままRailsを起動するとDBに接続できずにエラーが起きるのでパスワードを設定します。
/config/database.ymlを編集してDBのユーザ名とパスワードを設定します。

/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: yourusername #ユーザ名を入力
  password: yourpassword #パスワードを入力
  socket: /var/run/mysqld/mysqld.sock

パスワードを指定したら、DBを作成します。

bundle exec rails db:create

DBの作成が成功したらrails sでサーバーを起動。
もしサーバーのアドレスがlocalhostでない場合、IPアドレスを-bオプションで指定しましょう。

bundle exec rails s -b サーバーのIPアドレス

/sampleにアクセスして、Vueで指定したnameが表示されていれば、成功です。

コンポーネントを導入する

Vue.jsの導入に成功したので、次はコンポーネントを導入します。

entry.jsをできるだけ汚したくないため、親となるコンポーネントvueSample.vueを呼び出し、親コンポーネントからvueSampleItem.vueを子コンポーネントとして呼び出します。

データは親コンポーネントで保持し、データが変更されると自動的に子コンポーネントに反映されるように実装します。

/frontend/src/javascripts/components/vueSample.vue
<template>
  <div>
    <div>{{message}}</div>
    <div>
      <!-- samplesに格納された配列を元に表示する -->
      <!-- idとnameを子コンポーネントに渡す -->
      <!-- keyはあったほうがいいと思われる -->
      <vue-sample-item v-for="sample in samples" 
        v-bind:key="sample.id"
        v-bind:name="sample.name"
        v-bind:id="sample.id" 
      >
      </vue-sample-item>
    </div>
  </div>
</template>
<script>
import vueSampleItem from './vueSampleItem';

export default {
  name: 'vueSample',
  data: function(){
    return {
      //samplesがデータを入れる配列
      //この配列を編集すると自動的に表示に反映される
      samples: [
        {
          id: 1,
          name: 'sample1'
        },
        {
          id: 2,
          name: 'sample2'
        },
        {
          id: 3,
          name: 'Sample3'
        }
     ],
      //表示したいメッセージ
      message: 'Message'
    }
  },
  //子コンポーネントを指定する
  components: {
    'vue-sample-item': vueSampleItem
  }
}
</script>
/frontend/src/javascripts/components/vueSampleItem.vue
<template>
  <div class="vuesampleItem" v-bind:class="{active: isActive}">
    <p v-on:click="toggleActive();">
      {{name}}
    </p>
  </div>
</template>

<script>
export default {
  name: 'vueSampleItem',
  //親コンポーネントから受け取るプロパティ
  //型はできるだけ指定した方がよいとされる
  props: {
    id: Number, 
    name: String 
  },
  data: function(){
    return {
      isActive: false
    } 
  },
  methods: {
    toggleActive: function(){
      this.isActive = !this.isActive;
    },
  }
}
</script>

<style lang="scss" scoped>
  .vuesampleItem {
    border: 1px dashed #abcdef;
    margin: 4px 0; 

    &.active {
      border-left: 10px solid #abcdef;
    }

    &:hover {
      background-color: #fafafa;
    }

    p {
      margin: 0;
      padding: 4px;
    }
  }
</style>

コンポーネントごとに、HTML/CSS/JavaScriptをまとめて記述できました。

コンポーネントの詳しい解説は、基礎から学ぶ Vue.jsなどの資料を参考してもらえればと思います。
(コンポーネントの解説だけで大きな分量になります。)

コンポーネントを読み込むため、entry.jsを修正します。

/frontend/src/javascripts/entry.js
import Vue from 'vue';

//↓追加
import vueSample from './components/vueSample';

document.addEventListener("DOMContentLoaded", function(event) {
  new Vue({
    el: '#app',
    data: {
      name: 'aaa',
    },
    //↓下を追加。上のカンマも忘れずに。
    components: {
      'vue-sample': vueSample
    }
  });
});

最後にビューを修正して親コンポーネントを配置します。

/app/views/samples/index.html.erb
<div id="app">
  <%# 親となるコンポーネントを指定する %>
  <vue-sample></vue-sample>
</div>

npm run buildで更新します。
成功していれば、samplesに格納した配列の通りに表示されているはずです。
名前をクリックすると、classを切り替えることができます。

Railsと通信してDBと連携する

ここまでは配列に直接入力したデータを参照していました。
次は、Railsと通信してDBのデータを取得します。

データ一覧の表示、データの作成、更新、削除の機能を実装していきます。

DBの設定

Railsのモデルを作成します。

Shell
bundle exec rails g model sample

成功するとメッセージが表示されます。

invoke    active_record
create    db/migrate/20190727062002_create_samples.rb
create    app/models/sample.rb
invoke    test_unit
create    test/models/sample_test.rb
create    test/fixtures/samples.yml

/db/migrate/以下に新しいマイグレーションファイルができているので、編集します。
名前を保存するため、string型でnameカラムを追加します。

/db/migrate/[日付]_create_samples.rb
class CreateSamples < ActiveRecord::Migration[5.2]
  def change
    create_table :samples do |t|
      t.timestamps
      # ↓追加
      t.string :name, default: ""
    end
  end
end

成功したら、nameカラムを追加するためマイグレーションを追加します。

Shell
bundle exec rails db:migrate

成功するとnameカラムが追加されます。

DBの情報を取得するためのアクションを追加

Rails側からDBの情報を送信するためのアクションを作ります。
作成するアクションは下の通りになります

アクション名 役割
index レコード一覧の表示
create レコードの新規作成
update 指定したidのレコードの更新
destroy 指定したidのレコードを削除
all 全レコードの取得

all以外はresourcesから自動生成されます。

ルーティングを変更するため、routes.rbを編集します。

/config/routes.rb
Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
  resources :samples, only: [:index, :create, :update, :destroy] do
    collection do
      get "/all", to: "samples#all"
    end
  end
end

次に、コントローラを編集します。

all create update の各メソッドは、idカラムとnameカラムの情報を連想配列で返します。
destroyメソッドはidカラムのみを返します。
失敗した場合、例外を起こす(update!などのメソッドを使用する)ようにして、失敗をクライアント側で検出できるようにしました。
(失敗した場合、Internal Server Errorになります)

getsampleメソッドは、インスタンス変数@sampleに指定したidを自動的に格納します。
sample_to_hashメソッドは、取得したデータから必要な情報(idname)を抜き出すメソッドになります。

/app/controllers/samples_controller.rb
class SamplesController < ApplicationController
  before_action :getsample, only: [:update, :destroy]

  def index
  end

  def all
    samples = Sample.all
    result = []
    samples.each do |sample|
      hash = sample_to_hash(sample)
      result << hash
    end
    render :json => result
  end

  def create
    name = params[:name]
    sample = Sample.new({
      name: name,
    })
    sample.save!

    result = sample_to_hash(sample)
    render :json => result
  end

  def update
    @sample.update!({
      name: params[:name],
    })
    result = sample_to_hash(@sample)
    render :json => result
  end

  def destroy
    @sample.destroy!

    result = {
      id: params[:id],
    }
    render :json => result
  end

  private

  def getsample
    @sample = Sample.find(params[:id])
  end

  def sample_to_hash(sample)
    hash = {}
    hash[:id] = sample.id
    hash[:name] = sample.name
    return hash
  end
end

コンポーネントからRailsに通信する

axiosのインストール

Rails側の準備ができたので、コンポーネントから通信してデータを読み込みましょう。

Vue.jsからの通信クライアントはaxiosが使われることが多いようです。
axiosをインストールします。

Shell
cd ./frontend
npm i --save axios

一覧の表示と、レコードの追加

最初に、レコードの一覧表示と新規追加を作ります。

レコードの一覧表示は、samplesの配列にデータをロードすることで自動的に作成できます。

新規レコードを追加するため、一覧ページの一番上にテキストフィールドと送信ボタンを配置します。
テキストフィールドに名前を入力し、ボタンを押すとpostで送信します。
テキストフィールドの内容を、newnameにバインディングし、送信ボタンがクリックされるとsendCreate()メソッドが呼び出されるようにします。
sendCreate()メソッドはnewnameを参照してpostを送信します。

/frontend/src/javascripts/components/vueSample.vue
<template>
  <div>
    <div>{{message}}</div>
    <!-- ↓下のdivタグを追加 -->
    <!-- 新規作成フォーム -->
    <div>
      <label>Name<input v-model="newname"></label>
      <button v-on:click="sendCreate();">Create</button>
    </div>
    <!-- 省略 -->
  </div>
</template>

スクリプトも変更します。
axiosを使用するため、インポートします。
railsとの通信のためCSRFトークンを用意する必要があるため、axiosにトークンを設定します。

/frontend/src/javascripts/components/vueSample.vue
<script>
import axios from 'axios';

import vueSampleItem from './vueSampleItem';

// set CSRF token
axios.defaults.headers.common = {
  'X-Requested-With': 'XMLHttpRequest',
  'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content')
};
// 省略
</script>

次にコンポーネント本体のスクリプトを修正します。

配列samplesに入力されていたデータを全て削除します。
変数newnameを追加します。

メソッドを追加します。

メソッド名 概要
getAllSamples() 全データの取得をするメソッド
sendCreate() レコードの新規作成のため、名前をRailsに送るメソッド
getLocation() 必ず最後に/が付くように自ページのURLを取得する
/frontend/src/javascripts/components/vueSample.vue
<script>
//省略
export default {
  name: 'vueSample',
  data: function(){
    return {
      //内容を空にする
      samples: [],
      //newnameを追加
      newname: '',
      message: 'Message'
    }
  },
  methods: {
    getAllSamples: function(){
      axios.get( this.getLocation() + 'all' )
      //成功したときのコールバック
      .then( function(response){
        this.samples = response.data;
        this.message = '取得に成功しました。'
      }.bind(this) )
      //失敗したときのコールバック
      .catch( () => this.message = '取得に失敗しました。');
    },
    sendCreate: function(){
      axios.post( this.getLocation(), {
        name: this.newname
      } )
      .then( function(response){
        //成功したらsamplesに項目を追加
        this.samples.push(response.data);
        this.message = '追加に成功しました。'
      }.bind(this))
      .catch( () => this.message = '追加に失敗しました。');
      //テキストフィールドを空にする
      this.newname = '';
    },
    getLocation: function(){
      let result = location.href;
      //最後に/がついていなかったら追加する
      if( !result.match(/\/$/) ){
        result += '/'
      }
      return result;
    }
  },
  //コンポーネントがマウントされると、getAllSamples()が呼ばれる
  mounted: function(){
    this.getAllSamples();
  },
  components: {
    'vue-sample-item': vueSampleItem
  }
}
</script>

完成したら、npm run buildを実行してwebpack.jsを更新します。
テキストフィールドに名前を入力して送信すると、要素が追加されるはずです。

データの編集

次にデータの編集ができるようにしましょう。
sendUpdateメソッドを作り、patchで更新します。

/frontend/src/javascripts/components/vueSample.vue
<script>
//省略
  methods: {
    //↓下を追加
    sendUpdate: function(_id, _name){
      axios.patch( this.getLocation() + _id, {
        id: _id,
        name: _name
      } )
      .then(function(response){
        this.message = '更新に成功しました。';
      }.bind(this))
      .catch( () => this.message = '更新に失敗しました。');
      // nameを書き換え
      // findメソッドで配列内を検索し、idが一致した要素の名前を変更する
      let target = this.samples.find( item => item.id == _id );
      target.name = _name;
    },
    //省略
  }
</script>

メソッドを追加しました。
しかし、これだけだとメソッドは実行されません。
子コンポーネントに更新のためのフォームを作り、メソッドを実行しないといけません。

vueSampleItem.vueを修正します。

テキストフィールドを作り、算出パラメータmyNameとバインディングします。
nameは親コンポーネントのデータなので、変更してはいけません。
代わりにmyNameが変更された際には親コンポーネントのsendUpdateメソッドを実行するように設定します。
sendUpdateメソッドは親コンポーネントのデータを変更することができます。

myNamedataに追加せず、算出パラメータとして設定します。
myNameにデータが書き込まれる際に、sample-updateイベントを自分自身に発生させます。
sample-updateイベントが発生した際に、親コンポーネントのsendUpdateメソッドが実行されるように設定します。
子コンポーネントからsample-updateイベントを起こすためには、$emitメソッドを使用します。

/frontend/src/javascripts/components/vueSampleItem.vue
<template>
  <div class="vuesampleItem" v-bind:class="{active: isActive}">
    <p v-on:click="toggleActive();">
      {{name}}
    </p>
    <!-- ↓下のpタグを追加 -->
    <p>
      <input v-model="myName">
    </p>
  </div>
</template>
<script>

export default {
  name: 'vueSampleItem',
  props: {
    id: Number, 
    name: String 
  },
  data: function(){
    return {
      isActive: false
    } 
  },
  //computedを追加
  //myNameは算出パラメータとして設定
  computed: {
    myName: {
      //読み取りはnameを参照
      get: function(){
        return this.name
      },
      //書き込みはsample-updateイベントを自分自身に送信する。
      //sample-updateイベントが発生すると、
      //親コンポーネントのsendUpdateメソッドが発生するように設定する
      set: function(val){
        if (this.name !== val){
          this.$emit('sample-update', this.id, val);
        }
      }
    }
  },
  //ここまで追加
  methods: {
    toggleActive: function(){
      this.isActive = !this.isActive;
    },
  }
}
</script>

sample-updateイベントが発生した際に、sendUpdateメソッドが呼び出されるように親コンポーネントを設定します。

/frontend/src/javascripts/components/vueSample.vue
<template>
  <!-- 省略 -->
  <!-- v-on:sample-updateイベントが発生すると、sendUpdateメソッドが呼び出される -->
  <vue-sample-item v-for="sample in samples" 
    v-bind:key="sample.id"
    v-bind:name="sample.name"
    v-bind:id="sample.id" 
    v-on:sample-update="sendUpdate"
  >
  </vue-sample-item>
  <!-- 省略 -->
</template>

npm run buildでビルドします。
テキストフィールドの内容を変更すると、DBが更新されます。

レコードの削除

最後にレコードの削除を実装します。

子コンポーネントに削除ボタンを作り、クリックすると削除されるように実装します。

/frontend/src/javascripts/components/vueSampleItem.vue
<template>
  <!-- 省略 -->
  <!-- ↓下を追加 -->
  <p>
    <button v-on:click="sendDelete();">delete</button>
  </p>
  <!-- 省略 -->
</template>

sendDeleteメソッドを追加します。
データを更新した時と同じように、sample-deleteイベントを発生させます。

/frontend/src/javascripts/components/vueSampleItem.vue
<script>
  //省略
  methods: {
    toggleActive: function(){
      this.isActive = !this.isActive;
    },
    // ↓下を追加
    sendDelete: function(){
      this.$emit('sample-delete', this.id);
    },
  }
  //省略
</script>

更新の時と同じように親コンポーネントも変更します。

/frontend/src/javascripts/components/vueSample.vue
<template>
  <!-- 省略 -->
  <!-- sample-deleteイベント発生時にsendDelete()メソッドを実行する -->
  <vue-sample-item v-for="sample in samples" 
    v-bind:key="sample.id"
    v-bind:name="sample.name"
    v-bind:id="sample.id" 
    v-on:sample-update="sendUpdate"
    v-on:sample-delete="sendDelete">
  </vue-sample-item>
  <!-- 省略 -->
</template>
<script>
  // 省略
  methods:{
    //sendDeleteメソッドを追加
    sendDelete: function(_id){
      axios.delete( this.getLocation() + _id )
      .then(function(response){
        this.message = '削除に成功しました。';
      }.bind(this) )
      .catch( () => this.message = '削除に失敗しました。');

      //配列を更新
      //idが一致しない要素だけを抜き出して新しい配列を作る
      this.samples = this.samples.filter(item => item.id !== _id);
    },
  },
  //省略
</script>

npm run buildで更新します。
成功していれば、削除ボタンでデータを削除することができるはずです。

さいごに

RailsVue.jsを組み合わせて、CRUDを実現することができました。

最初にVue.jsを導入しようとしたきっかけはReactと違いトランスパイルが不要、ということでRailsに組み込みやすいかなあと思ったためでした。
しかし、結局のところ単一ファイルコンポーネントが使いたくなったため、Webpackの導入から始める必要が出てきてしまいました。

Railsのアセットパイプラインは、最近では欠点といわれることが多いようです。
それでもRailsのActiveRecordは評価が高く、DB周りでは今後もRailsが多く使われていくかと思います。

RailsにWebpackを導入してVue.jsを利用することは、Rails初心者には少し敷居が高いかなあと思っています。
しかし、この記事をきっかけにして少しでもVue.jsを触ってみたいと思ってもらえたら、動かしながら学んでもらえたら、嬉しいと思います。

サンプルコードについて

サンプルコードを、GitHubにアップロードしましたので、ご自由にご利用ください。
ただし、利用した結果については、責任を負いかねます。

パッケージについてはインストールされていないので更新が必要です。
DBの設定を変更した後、

bundle install --path=vendor/bundle
cd frontend
npm install
cd ..
bundle exec rails db:create
bundle exec rails db:migrate

といった感じで実行できると思います。

16
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
15