Rails+Vue.jsでバリデーションエラーを各項目の下に表示する


はじめに

Rails側のモデルに定義したバリデーションを使いつつ、
バリデーションエラーを各項目の下に表示するのに苦労したのでまとめておこうと思います。
今回、バリデーション関連以外の説明は省略させていただきます。
ご了承ください。。

やりたいこと

このように項目の下にバリデーションエラーを表示するようにします。(見た目は気にしないでください。。)

実装してみる

バリデーションを設定

ここでは必須のバリデーションだけ設定しておきます。

class Company < ApplicationRecord
  validates :name,
    presence: true
end

API側の実装

vue.js側で各項目ごとのエラーメッセージを取り出せるようにします。
具体的には下記のようなハッシュになるように加工します。
{項目名: 日本語化されたエラーメッセージ}

今回は下記のように実装しました。

@company = Company.new(create_company_params)
if @company.save
  render json: @company, status: :ok
else
  render json: { errors: @company.errors.keys.map { |key| [key, @company.errors.full_messages_for(key)]}.to_h, render: 'show.json.jbuilder' }, status: :unprocessable_entity
end

ここでerrorsにエラーメッセージを設定しています。

errors: @company.errors.keys.map { |key| [key, @company.errors.full_messages_for(key)]}.to_h

API側はこれで終わりです。

vue.js側で項目の下にエラーが表示されるようにする

まずはtemplateから実装していきます。

<template>
  <form @submit.prevent="createCompany">
    <h2>企業情報</h2>
    <div>
      <label>企業名</label>
      <input v-model="company.name" type="text">
      <!-- これでバリデーションエラーがあるときだけ表示される -->
      <p v-if="!!errors['name']" class="error" style="color: red;">{{ errors['name'][0]}}</p>
    </div>
  </form>
</template>

errorsのkeyの中に表示する項目名が含まれているかどうかで、
表示/非表示を切り替えています。

次にscriptです。

<script>
  import axios from 'axios'
  import { csrfToken } from 'rails-ujs'
  axios.defaults.headers.common['X-CSRF-Token'] = csrfToken()

  export default {
    data: function () {
      return {
        company:{
          name: ''
        },
        // バリデーションエラーがあった場合は、このerrorsにセットされます。
        errors: ''
      }
    },
    methods: {
      createCompany: function(){
        axios
          .post('api/v1/company.json', this.company)
            .then(response => {
              this.$router.push('/');
            })
            .catch(error => {
              if (error.response.data && error.response.data.errors) {
                this.errors = error.response.data.errors;
              }
            });
      }
  }
</script>

これでバリデーションエラーがあるときは各項目の下に表示されるようになるかと思います。

まとめ

今回は各項目の下にエラーメッセージを表示する方法をまとめました。
もっといい感じの方法があれば、是非コメントで教えてください。。