railsのプロジェクトにおけるvueを使った開発手法

今回はrailsのプロジェクトにおいてフロントにvue.jsを導入してみたことを記事にしてみました。具体的には下記のやりたいことに書いてあります。

開発環境

  • vue:2.3.4
  • typescript:2.2.2
  • ruby2.4.2
  • rails5.2.0

やりたいこと

railsjavascriptフレームワークなどを使用せずに開発をする場合コントローラーで作ったインスタンス変数などをerb.htmlファイルに渡すことが多いと思います。

f:id:top_men:20180617155702p:plain

今回は冒頭にも書きましたがvueの単一ファイルコンポーネントを使用して開発することを前提としています。そこで.vueファイルにrails側で作成したデータを渡す必要があります。erb.htmlファイルなら直接rubyのコードを記述することができますが、.vueファイルはrubyのコードを書くことができません。 

そこでどうしたら上記の問題を解決できるのか悩んでいました。

結論を言いますとwindowオブジェクトにviewmodelを追加すれば良いということです。

ここでは実際にユーザー情報が書かれたユーザ一詳細ページを例に解説していきます。(※ディレクトリ構成については説明していないのでご了承ください。)

ユーザー詳細ページの例

windowオブジェクトにviewmodelを追加している部分

import { Vue, Component } from 'vue-property-decorator';
import User from "../../component/users/User.vue";

@Component({
  components: {
    "user-profile-component": User
  }
})

class UserProfile extends Vue {

}

(<any>window).UserProfile = UserProfile;

前提としてtypescriptを使用して開発をしています。今回はそのことについてはあまり触れないので詳細を知りたい方は以下のリンクを参考にしてみてください。

github.com

はじめに、表示する用のUserコンポーネントを登録しています。 その後、windowオブジェクトのプロパティとしてUserProfileクラスを登録しています。

// typescriptを使用した記述方法

(<any>window).UserProfile = UserProfile;

// typescriptを使用していない場合

window.UserProfile = UserProfile

viewModelをインスタンス化している部分

<div id="userProfile">
  <user-profile-component :user="user"></user-profile-component>
</div>
<%= javascript_include_tag "/javascripts/viewmodel/users/show" %>
<script>
  new UserProfile({
    el: "#userProfile",
    data: {
      user: <%= raw @user.to_json %>
    }
  })
</script>

ここでviewファイルである.erb.htmlファイルとvueインスタンスをバインドしています。 その中にユーザー詳細ページを表示するコンポーネントを配置してpropsrailsからのデータを渡しています。

<user-profile-component :user="user"></user-profile-component>
<script>
  new UserProfile({
    el: "#userProfile",
    data: {
      user: <%= raw @user.to_json %> // railsのデータをインスタンス変数のuserに代入
    }
  })
</script>
<%= raw @user.to_json %>

このto_jsonメソッドは、rubyのHashやArrayをjson形式に変換してくれています。こうすることでフロント側で受け取りやすいデータ構造になります。

to_jsonを使った簡単な例

f:id:top_men:20180617142202p:plain

to_jsonを使用すると

f:id:top_men:20180617142310p:plain

json形式に変換してくれましたね。

またrawメソッドも使う必要があります。 使った場合と使わない場合の出力結果を見てみましょう。 (ここではdebuggerを仕込んだ出力結果を見ています。)

  • rawメソッドを使わない場合

f:id:top_men:20180617144556p:plain

  • rawメソッドを使った場合

f:id:top_men:20180617144831p:plain

ダブルクォーテーション""&quot;と変換されているのがわかります。 つまりrawメソッドを使用しない場合は、自動的にエスケープされています。 エスケープされないためにrawメソッドを使用する必要があるのです。

railsから受け取ったデータを受け取って描画している部分

<template>
  <div class='user'>
    <div class='user_name'>{{user.name}}</div>
    <div class='user_email'>{{user.email}}</div>
  </div>
</template>

<script lang="ts">
import { Vue, Prop } from "vue-property-decorator";
import UserData from "../../data/user";

export default class User extends Vue {
  @Prop()
  public user: UserData;
}

</script>

.vueファイルでは親から値を取得するためにpropsを定義してあげます。 あとは目的に合わせて表示するだけです。

まとめ

vueの単一ファイルコンポーネントを使用ってrailsからvueファイルにデータ渡すことができました。今回はvueを例に紹介しましたがreactなど他のフレームワークでも上記で説明した手法で開発できると思います。 簡単ではありますが、以上になります。