Railsのwebpackを使用して、SPAの開発ができるということで、実際に開発しているが、あまり、Rails + Vue.jsの開発メモがなかったので、はまったところなどメモしたいと思う。
開発環境の構築、Vue.jsの使い方などは、今回は割愛させていただきます。
2019/01/27 後述
RailsとVue.jsを共存させるというのは難しいなと一通り開発してみて感じた。本来、コードをスマートにするために使われるフレームワークの良さが失われてしまう。2018年の1年間フロントまわりの技術をさらってみて、本記事のようにサーバーサイドとフロントを共存させてしまうよりも、サーバーサイドはAPIとしての役割のみ持たせて(RailsにはAPIモードがある)、あとはフロントに任せるという、双方のコードを分離させた方が開発がスムーズになると今は考えている。そのため本記事の方法はあまり推奨しない。
環境情報
Ruby 2.4.0
Rails 5.1.0
rails/webpacke 3.1.0
Vue.js 2.5.13
vue-router3.0.1
Vueファイルを使用する
vue.jsを導入した時にできるファイルhello_vue.jsがvue.jsを動かす基盤となる。
トップページを作ってみる
import Vue from 'vue/dist/vue.esm'
import router from './routes.js';
document.addEventListener('DOMContentLoaded', () => {
const app = new Vue({
el: '#app',
router
})
});
importで、yarnで導入したライブラリを読み込む。この場合だと、vue/dist/vue.esmを使用するよ〜、./routes.js(こいつは、後で触れるが、ルーティングの設定をしているファイル)を使用する宣言をしている。それぞれ、Vueやrouterという名前をつけて、Vueのインスタンス化をするときに、読んであげる。それが、new Vue({})の中である。el: '#app'
というのは、Vueのルールで、このappで囲まれたところでしか、Vueは使えない。
vue-routerを使用する
vue.jsのルーティングはvue-routerを使用してあげる。先ほどの、hello_vue.jsに記述した。
import Vue from 'vue/dist/vue.esm';
import VueRouter from 'vue-router';
import Index from './components/app.vue';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Index, name: 'root_path' },
]
});
export default router;
先ほどのhello_vue.jsと同様。どのファイルを使用するかを記述する。
{ path: 'アクセスされるURL', '使用するコンポーネント', 'pathの名前'}
こんな感じのルールで書く。これで、トップページにアクセスすると、app.vueで記述した画面に遷移するように設定ができた。
ここまで、作ったものをレイアウトに乗せてあげればOK。
あとは、このrouterを使用するために、Railsのapplication.html.erbにrouter-viewタグを追加する。
<head>
<%= javascript_pack_tag 'hello_vue' %>
</head>
<body>
<div id="app">
<router-view></router-view>
</div>
</body>
こうすることによって、先ほど、hello_vue.jsで書いたid = appの下はvue.jsが動くので、appのdivでrouter-viewを挟んであげれば、指定されたpathに対して、componentsを描画するというようにvue.jsが動くようになる。
実際に開発する
てな、感じでトップページは作ることは簡単にできるのだが、実際に開発してみるとハマるポイントが多い。
実際に作業の流れを例に示す。
①vue.jsでフォームを作る
まずは、先ほどと同じ要領で、ルーティングの設定をする。
import Vue from 'vue/dist/vue.esm';
import VueRouter from 'vue-router';
import Index from './components/app.vue';
import Question from './components/question.vue';
Vue.use(VueRouter);
const router = new VueRouter({
mode: 'history',
routes: [
{ path: '/', component: Index, name: 'root_path' },
{ path: '/question/new', component: Question, name: 'question_new_path' },
]
});
export default router;
question/newというパスにきたら、Questionコンポーネントを使用するようにルーティング設定。Questionコンポーネントは、question.vueというファイルをcomponentsの下に新規追加する。
<template>
<div>
<div class="container">
<form>
<div class="form-group">
<label for="form_title">質問名</label>
<input type="text" name="question[content]" class="form-control" id="content">
<button type="button" class="btn btn-primary" v-on:click="postQuestion">作成する</button>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
data: function () {
return {
question: {
content: null,
},
}
},
methods: {
}
}
</script>
ただ、これだけだと、/question/newにアクセスしてもRailsのルーティングエラーになってしまう。
そのため、Railsの開発同様、Question_cotroller.rbとviews/questions/new.html.erb、そして、rails側のルーティングも記述しないといけない。
②保存処理を実装する
ここまでで、DBなどを活用しない画面は作ることができるが、やはりシステムを作るなら、DBに値を保存する機能が必須である。
ここからは、Vue側から、Railsに値を渡してデータを保存する機能を作って行く。
データを保存する際には、ajax処理を使うのだが、せっかくVue.jsを使っているので、axiosを使用する。
yarn add axios
でaxiosをインストールしたら、
<script>
import axios from 'axios'
export default {
data: function () {
return {
question: {
content: null,
},
question_id: null
}
},
methods: {
postQuestion: function(){
axios.post('/api/quetion', {
content: this.question.content,
}).then((res)
this.question_id = res.data._id
});
}
}
}
</script>
postの第一引数に、保存処理をするコントローラーのパス、第二引数に値を渡せば簡単にajax処理ができる。
def create
begin
@question = Question.create!(question_params)
respond_to do |format|
format.html { redirect_to @question, notice: 'Question was successfully created.' }
format.json { render :new, status: :created, location: @question }
end
rescue => e
logger.error(e.message)
format.html { render :new }
format.json { render json: @question.errors, status: :unprocessable_entity }
end
end
def question_params
params.require(:question).permit(
:content
)
end
基本的に、サーバーサイドに値が渡ってきたら、Railsのやり方でやればOK
③サーバーサイドからの値を取得する
Railsの場合、コントローラーから変数をerbファイルに渡すことができたが、vue.jsの場合はそれができない。
そのため、基本的に値はコントローラーでjsonデータをjson.jbuilderを使ってview側に渡す形になる。
json.question_id @question.id
基本的に、これらの要領でいけば、VueとRailsを使ってデータのやり取りができるはず。
参照
Vue.jsとRailsでTODOアプリのチュートリアルみたいなものを作ってみた
Vuejs – RE:ENGINES
Rails 5.1 + Vue.js で開発を行う - part2 Ajax で GET しよう!