カクカクしかじか

技術的なアレコレ

Railsのerb経由でVueコンポーネントに値を受け渡す方法

動作検証した各ライブラリバージョン

  • Rails : 4系(5系でも問題なく動きそう)
  • Vue.js : 2.5.13

注意

サンプルコードは実際のコードを抽象化したものであるため雑に抽象化されて分かりにくいかもしれません

想定されるアプリの構成

  • gem 'webpacker' を使用してRails上でVue.jsを動かしているアプリケーション
  • Vueコンポーネントはerbに埋め込む形で使用しており、Railsと密結合な中でVue.jsを使う場合

erbからVueコンポーネントに値を渡したい場合の例

  1. 会員登録時に送信されるアクティベーションメールに記載されたリンクをクリックするとGETでユーザーのアクティベーションのアクションが呼ばれる
  2. そのアクションでは個人情報入力フォーム用テンプレートの描画を行う必要がある
  3. render テンプレート名 をする一方で任意の値をVueフォームコンポーネントに渡したい

この場合に問題になること

以下にサーバーサイドの実装サンプルを記載

hoges_controller.rb

# 会員アクティベーション用のメールに記載されたアクティベーションのリンクをクリックした後に呼ばれるアクションだと仮定
# GETでアクセスしてくる
def activate
  # 何らかの処理
  # hoge.html.erb を hoge というlayoutファイル上で表示したい
  # localeでerbにサーバーサイドの値を渡す
 render 'hoge', layout: 'hoge', locals: { user_name: user_name }
end

ここでネックになるのが、render json: { key: value } ならVueコンポーネント上で直接投げられた値に this でアクセス出来るが今回は render json で値を渡せないこと。

今回やることの大まかな流れ

  1. コントローラーからlocalsでerbに値を渡す
  2. サーバー側で渡した値をerbからVueコンポーネントに渡す
  3. Vueでerbの値を受け取る

1. コントローラーからlocaleでerbに値を渡す(Rails側)

  • サーバーサイドからlocale経由でerbへ値を渡す

hoges_controller.rb

# 会員アクティベーション用のメールに記載されたアクティベーションのリンクをクリックした後に呼ばれるアクションだと仮定
# GETでアクセスしてくる
def activate
  # 何らかの処理
  # hoge.html.erb を hoge というlayoutファイル上で表示したい
  # localeでerbにサーバーサイドの値を渡す
 render 'hoge', layout: 'hoge', locals: { user_name: user_name }
end

2. サーバー側で渡した値をerbからVueコンポーネントに渡す(Rails側)

  • hoge-formコンポーネントに属性として直接そこに値を記述する(コントローラーからはlocalsで値が渡されている)
hoge.html.erb
<div>
 <hoge-form user_name="<%= user_name %>"></hoge-form>
</div>

3. Vueでerbの値を受け取る(Vue.js側)

  • erbから受け取った値をデフォルトでコンポーネント描画時に表示したいという想定
  • propsでerbから受け取りたい値を定義しておく
  • propsに記載した値はdataプロパティには改めて定義しなくて良い
HogeForm.vue
<template>
  <div class="user_name">
    // ここでpropsで定義した値を受け取って描画出来る
    {{ user_name }}
  </div>
  <dl class="form_mail">
    <dt class="input_title">メールアドレス</dt>
    <dd class="input_mail">
      <input
       v-model="email"
       type="email"
       placeholder="sample@sample.jp"
      >
    </dd>
  </dl>
  <dl class="form_password">
    <dt class="input_title">パスワード</dt>
    <dd class="input_password">
      <input
       v-model="password"
       type="password"
       placeholder="password"
      >
    </dd>
  </dl>
  <div class="register_button">
    <button
     class="btn btn_send_long"
     @click="onSubmit"
    >登録
    </button>
  </div>
</template>

<script>
  export default {
    props: {
    // 今回大事なのはここ!propsでerbから受け取る値を定義しておくこと
    // typeでStringを指定しておくことで文字列以外をエラーに出来る
      user_name: { type: String, default: null }
    },
    data: function () {
      return {
        // 任意のプロパティ
        email: '',
        password: ''
      };
    },
    methods: {
      // 任意のfunction
      async onSubmit () {
        // 何らかの処理
      }
    }
  };
</script>

これでサーバーサイドの値をerb経由でVueコンポーネントに渡すことが出来ます!