Rails
form
vue.js

Railsのform要素をVue.jsで操作したいときにどうやって初期値を取得したらいいのか考えてみる

フォーム要素をまるっと Vue.js で管理したいとき v-model を指定すると初期値が Vue.js 側の値で上書きされて、フォームにもともと指定してあった value の値が無視されてしまう問題にいまごろ直面しました。

もともと Vue.js 1系のころは v-model で指定した値にフォームの初期値が入っていたそうなのですが2系からは入らなくなったようです。

そこで先人が考え出したアイデアがこちらです。とても興味深いです。

Railsのフォームビルダーで生成したform要素をVueコンポーネント化する
https://qiita.com/kuroda@github/items/940338b5f6f46da2c5f1

記事を拝見する前、私はひとつひとつの input に ref 属性をつけて this.$refs.xxx として値を取得する方法を試みていたのですが querySelector という手があったかと感心しました。さらには完全にライブラリ化&ブラックボックス化しており、同じコードは二度と書かねえという心意気を感じます。scaffold で生成したフォームを Vue.js で管理できるようにする目的であればできてます。

ただ、 Vue.js でフォームを管理できるようになると、いろいろやりたくなってくるんです(笑) いろいろやるにはデータは全部欲しいわけです。フォームに無い値も使いたくなるんです。

上の方法ではデータは HTML のタグ経由なので、データを渡すために input タグを定義するという変な感じになってきます。そうなるともう最初から Vue.js にデータを全部まるっと渡しとけばいいんじゃねってことになります。で、これに行きつきました。

app/javascript/packs/user_form.js
import Vue from "vue/dist/vue.esm"

window.UserForm = Vue.extend({
  data() {
    return {
      user: this.$options.user_attributes,
    }
  },
})
(slim)
#app
  = form.text_field(:foo, "v-model": "user.foo")
  = form.text_field(:bar, "v-model": "user.bar")

javascript:
  new UserForm({user_attributes: #{form.object.to_json.html_safe}}).$mount("#app")

Vue.js のクラスは一箇所で定義して、それを使うときに form.object を全部渡してインスタンス生成します。当初は propsData で渡したりしていましたが、それはテスト用らしいので、普通に引数で渡して $options で参照する方法にしました。

けっこうシンプルでいいかなと思うんですが、こういうのどうなんでしょう?