RailsとVueに関して今まで流れがわからなかったのですが、
色々いじっていたらようやく流れが理解できてきたので見返せるようにメモ書きをします。
初学者なので理解が間違っている可能性が非常に高いため参考程度に!
一般的な正解ではなく、あくまで私の理解と納得解です。
###環境
MacOS Mojave
Ruby 2.6.4
Rails 6.0.3.3
Vue 2.6.12
Webpack 4.44.2
yarn 1.22.5
Docker 2.3.0.5
VScode
Vuetify
Vue-router
Vue-Store
####ブラウザからroutes.rbまで
この記事では、以下のURLを使います。
http://localhost:3000/
http://localhost:3000/user
はじめに、WebブラウザからURLを入力します。
http://localhost:3000/
Rails.application.routes.draw do
root to: 'home#index'
get "/user", to: 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
ブラウザからRailsサーバへURLが送られます。
http://localhost:3000/のURLを指定しているため
routes.rbの"root to: 'home#index'"の読み込み先が
参照されます。
####ルートからコントローラー
homeコントローラーのindexの関数が呼び出されます。
class HomeController < ApplicationController
def index
end
end
ちなみに正しいか分かりませんがroutes.rbも参照されるコントローラーも
毎回インスタンスが作成されている認識です。
だからルート間やコントローラ間で関連性がないのです。
本題に戻りますが、indexの関数が呼び出されます。
今回何も無いのでindexにマッチするVeiwファイルが参照されますが、
index関数内に@home = Home.allのようなモデルのインスタンスを作成する
プログラムがあった場合、モデルインスタンスが作成されて、
必要あればモデルがデータベースから情報を取得して@homeインスタンスに格納する
ステップがあるはずですが、今回は使用しません。流れとして覚えておきます。
####コントローラーからVeiwファイル(erbファイル)
コントローラーのindex関数が対応するファイルを参照します。
veiw/home/index.html.erbを参照します。
ここでは以下の設定が投入されていますが、
これは、app/javascript/pack内のhello.vueファイルを参照することを意味します。
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>
####Veiwファイル(erbファイル)からhello.vue(jsファイル)
Vueアプリケーションを使用するための根幹のファイルですね。
拡張子がVueの各ファイルはオブジェクトでまとまってこのファイルに
結合されるイメージです。
render: h => h(App)
で分かりますがapp.vueのテンプレートを
呼ぶことで app.vueの内容が表示されます。
このファイルはVueの各機能を使えるようにしてくれるものでして
このファイル自体にプロントの内容が記入されているわけではないです。
裏側で管理してくれる感じのファイルです。
vuetify,
router,
store,
を定義してVueで使えるようにしています。
親コンポーネントファイルはAppとしています。
SPAを実現しているのはrouterで
データを格納するのがvuexで
UIのフレームワークがvuetifyです。
import Vue from 'vue';
import App from '../src/components/app/app';
import Vuetify from 'vuetify';
import router from '../src/router';
import store from "../src/vuex/index"
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);
const vuetify = new Vuetify();
document.addEventListener('DOMContentLoaded', () => {
const app = new Vue({
vuetify,
router,
store,
render: h => h(App)
}).$mount()
document.body.appendChild(app.$el)
console.log(app)
})
次に見ていくのはAppファイルです。
####hello.vue(jsファイル)からapp.vue(vueコンポーネント)
すごくシンプルにしていますが、
このファイルが親コンポーネントでこのファイルがブラウザに表示されます。
しかし
<router-view></router-view>
がいることで
hello_vueでroute機能を持たせているためrouteが待ったを掛けます。
<template>
<div>
<router-view></router-view>
</div>
</template>
####app.vue(vueコンポーネント)からrouter.js(URLによってコンポーネントを決める)
route機能を持つとURL情報に従って指定のコンポーネントを返すようになります。
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from "../src/components/home/Home"
import User from "../src/components/user/User"
Vue.use(VueRouter);
export default new VueRouter({
mode: 'history',
routes: [{
path: '/',
component: Home
}, {
path: '/user',
component: User
}]
});
ブラウザでhttp://localhost:3000/
を打ちましたので
{
path: '/',
component: Home
}
によりHomeのコンポーネントを返すように決まりました。
はじめのほうのroutes.rbにて
root to: 'home#index'
のルート情報と連動しているのでURL情報をvueでも取得できています。
####router.js(URLによってコンポーネントを決める)からHome.vue(子コンポーネント)
VueのルートにてURL情報から表示するコンポーネントを決めたので
ここでの対象コンポーネントであるHome.vueを見ていきます。
<template>
<div>
<p>Home</p>
<p>{{ store}}</p>
</div>
</template>
<script>
export default {
computed: {
store(){
return this.$store.state.store
}
}
}
</script>
templateは実際にブラウザに表示される部分でscriptはjsの処理の部分ですね。
template内の
<p>{{ store }}</p>
を表示したいのでscript処理内を見ていきます。
computed: {
store(){
return this.$store.state.store
}
}
と書いてありますが、これは、Vuexを定義しているファイルの
state.storeのデータを持ってきてと言っていますのでvuexを定義しているファイルを見ていきます。
####Home.vue(子コンポーネント)からindex.js(vuexを定義したファイル)
import Vuex from 'vuex';
import Vue from 'vue';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
store: "Store"
}
});
ファイル名が分かりにくくすいませんがvuexを定義したファイルです。
store:"Store"
"Store"をstoreで定義しているので、どのコンポーネントからでもstoreと書けば"Store"を呼び出せます。
####index.js(vuexを定義したファイル)からHome.vue(子コンポーネント)
再びHome.vueへ戻ります。
<p>{{ store }}</p>
を表示したいのでscript処理内を見ていきます。
computed: {
store(){
return this.$store.state.store
}
}
scriptでvuexで"Store"を持ってきて、
{{ store }}
に入れて表示するという流れです。####Home.vue(子コンポーネント)からapp.vue(vueコンポーネント)
RouteでURLのコンポーネント(Home)が決まったと思います。
それをapp.vueにあった、に代入します。
<template>
<div>
<router-view></router-view>
</div>
</template>
下の
<router-view></router-view>
が
<template>
<div>
<p>Home</p>
<p>{{ store}}</p>
</div>
</template>
<script>
export default {
computed: {
store(){
return this.$store.state.store
}
}
}
</script>
に代入されます。
####app.vue(vueコンポーネント)からhello_vue.js
はじめの管理ファイルに戻ってきます。
app.vueファイルが全てオブジェクトになってhello_vue.jsに渡ってきます。
import Vue from 'vue';
import App from '../src/components/app/app';
import Vuetify from 'vuetify';
import router from '../src/router';
import store from "../src/vuex/index"
import 'vuetify/dist/vuetify.min.css';
Vue.use(Vuetify);
const vuetify = new Vuetify();
document.addEventListener('DOMContentLoaded', () => {
const app = new Vue({
vuetify,
router,
store,
render: h => h(App)
}).$mount()
document.body.appendChild(app.$el)
console.log(app)
})
以下のレンダー関数により
render: h => h(App)
全てのVueファイルがオブジェクトになって返されます。
####hello_vue.jsからVeiwファイル(erbファイル)
やっとRails側に戻ってきます。
全てのVueファイルがindex.html.erbに結合されます。
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>
####Veiwファイル(erbファイル)からコントローラー
ちょっと曖昧なのですが、最後にVeiwファイルをまとめてコントローラーがブラウザに返します。
ブラウザにhttp://localhost:3000/を打ち込んだら
Home.vueに記載されているHomeとStoreが返されました。
####同じように別のURLを打ったら?
別のURLで試してみます。
http://localhost:3000/user
上記のURLをブラウザで打ち込みます。
get "/user", to: 'home#index'
が使用されます。
コントローラーは同じで、erbも同じですので割愛します。
Rails.application.routes.draw do
root to: 'home#index'
get "/user", to: 'home#index'
# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from "../src/components/home/Home"
import User from "../src/components/user/User"
Vue.use(VueRouter);
export default new VueRouter({
mode: 'history',
routes: [{
path: '/',
component: Home
}, {
path: '/user',
component: User
}]
});
vue側のrouter.jsで以下のURLとコンポーネントが使用されます。
今回はUserコンポーネントです。
{
path: '/user',
component: User
}
Userコンポーネントは以下のようにシンプルです。
あとは同じようにrouteがapp.vueに結合してくれてhello_vueで表示してくれます。
後は同じ手順です。
<template>
<div>
<p>User</p>
</div>
</template>
Userが表示されました。
因みに、routerを使っているのになぜSPAにならないのか
(/と/user)で2回サーバにアクセスしに行っているのかですが、
ブラウザに直接URLを打ち込んでいるからです。
Home.vueやUser.vueで各コンポーネントに接続できるようにプログラムすれば
SPAを実現できます。