質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

SPA(Single-page Application)

SPA(Single-page Application)は、単一のWebページのみでコンテンツの切り替えができるWebアプリケーションもしくはWebサイトです。ブラウザでのページ遷移がないため、デスクトップアプリケーションのようなUXを提供します。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1170閲覧

(rails×vue)spaで作られたサイトはどの様にして直接アクセスの対策をしているのでしょうか?

widget11

総合スコア221

Vue.js

Vue.jsは、Webアプリケーションのインターフェースを構築するためのオープンソースJavaScriptフレームワークです。

Router

Routerは、異なるネットワーク同士を相互に接続するための通信機器。インターネットでのデータを自動的に振り分け、一つのインターネット回線を複数のコンピュータで使用することが可能です。DHCPによりIPアドレスを自動的に割振りすることもできます。

SPA(Single-page Application)

SPA(Single-page Application)は、単一のWebページのみでコンテンツの切り替えができるWebアプリケーションもしくはWebサイトです。ブラウザでのページ遷移がないため、デスクトップアプリケーションのようなUXを提供します。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

1クリップ

投稿2021/04/08 18:18

編集2021/04/11 20:09

vue.jsでルーティングにvue-routerを使うとして

import Vue from "vue"; import VueRouter from "vue-router"; Vue.use(VueRouter); import Page2 from '../pages/page2.vue' const routes =[ { path: '/page2', component: Page2 } ]; const router = new VueRouter({ routes, base: process.env.BASE_URL, mode: 'history' }); export default router;

以上の様なルーティングになっているとします。
$router.push等で/api/v1/users/3"に遷移しurl欄のurlも変化すると思います。
ただ実際これは非同期処理でDOMを書き換えているだけなので、
例えば直接パスを踏んだり、ブラウザの更新ボタン押したをするとサーバーサイドのルーティングを見に行ってしまうと思います。
例えばrailsのroutes.rbで

Rails.application.routes.draw do namespace :api do namespace :v1 do root to: 'home#index' resources :users, only: [:index,:show, :update] end end get '/page2', to: 'api/v1/users#show' end

この様に定義していたらこちらの/api/v1/users/3を見に行ってしまうという寸法です。
ユーザがブラウザの更新ボタンを押すということは至ってよくあることだと思うのですが、一般的にこれはどう対策すれば良いのでしょうか?(例えばrailsですと/users/show.html.erbを作成して、更新してもユーザからは同じページを表示してる様に見せるなど)
それとも更新を押してもusers.vueを呼び出す様ないい方法があるのでしょうか?
SPA周りがあまり詳しくなく疑問に思っています。よろしくお願いします。

###追記

js構成 javascript -packs |_pages2.js |_application.js -pages |_pages2.vue -router |_router.js
//application.html.erb <!DOCTYPE html> <html> <head> <title>PerformaApps</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <%= stylesheet_link_tag 'application', media: 'all' %> <%= javascript_pack_tag 'application' %> </head> <body> <%= yield %> </body> </html>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

HTML5 History モード
ここに載ってる方法を応用すれば良いです。

普通は nginx なんかで処理すると思いますが、rails のルーターでやるなら
以下のようにすれば良いんじゃないでしょうか(未確認)

Rails.application.routes.draw do # /app 以下は vue router get "/app/*path", to: "vueapp#index" end

ルーティンググロブとワイルドカードセグメント

追記

すみません。よく見たら rails の route と vue の route が重なっていますね。

別の URL にした方が良いと思いますが、どうしても同じ URL でやるなら
普通にアクセスされた場合と、xhr(axios)から呼ばれた場合でレスポンスを振り分ける必要があります。

ruby

1# これは削除 2get "/app/*path", to: "vueapp#index"

ruby

1# show の前に respond_to_direct_access を実行 2before_action :respond_to_direct_access, only: [:show] 3 4def show 5 # ここには axios 用の処理を書く 6 ... 7end 8 9private 10 11def respond_to_direct_access 12 # request.xhr は直接呼ばれた時は false 13 # axios から呼ばれたときは true になります 14 unless request.xhr # 直接呼ばれた時 15 # vue(とvue router)を含む javascript を返すビューを指定する 16 # この render が呼ばれると def show は呼ばれません 17 render "index" 18 end 19end

投稿2021/04/09 03:19

編集2021/04/10 04:27
neko_daisuki

総合スコア2090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

widget11

2021/04/09 17:51 編集

ご返信ありがとうございます! ただちょっと咀嚼しきれておらず https://sashimistudio.site/rails-vuerouter-history404/ このサイトでも僕の疑問と似た様な事象を解消しているのですが、 neko_daisuki様も記載している様な to: "vueapp#index" とindexアクションを指定する理由がわかりません。。。 routes.rbに resources :usersを削除し、 get 'users/*path', to: 'users#index' と記載してみたのですが、更新しても依然としてサーバーサイドをみにいっているみたいで。。。 そもそもresources :usersを消してしまうと、rails apiに記載しているshowアクションがルーティングされず、usersコンポーネント内でaxiosでコールしている`axios.get('http://localhost:3000/api/v1/users/3` というapiが通らなくなってしまいます。 何かとてつもない勘違いを僕はしてそうなのですが、記載している方法が間違っているのでしょうか? 理解力が足らずすみません。。。よろしくお願いします。
widget11

2021/04/11 19:09

ご返信ありがとうございます!!! railsのrouteとvueのrouteは分けた方が良いということで、分けて実装しました。(分けない方法についてもご教示ありがとうございます!) ただ分けた上で疑問に思ったのが、どうしても更新ボタンを押したり直接url表示するとサーバーのビューを表示(探す)してしまうのではと思ったことです。 例えば、vue-routerに const routes =[{ path: '/page2', component: Page2 } と記載ししてこのPage2コンポーネントでaxios.getするとします。 そして/page2というurlに直接アクセスが会った際の対策に get '/page2', to: 'app/index' と記載してみたのですが、app controllerというコントローラーはないのでルーティングエラーがおきます。 なので、get '/page2', to: 'api/v1/users#index' とコントローラーとアクションはないがテンプレートがあるパスを記載してみますが、missing templateをしてしまいます。 あくまでも更新ボタンを押したときにpage2コンポーネントを描画してもらいたいだけなのですが、、 全く解決できず。。大変申し訳ないですが、routes.rbのtoの先は何を記載するとpage2コンポーネントを描画してくれるのでしょうか? 理解が追いついておらず大変申し訳ございません。。
neko_daisuki

2021/04/11 19:20

vue(とvue router)を含む javascript を含むビューを返すアクションを指定します。 application.html.erb(のhead部分) と javascript の構成を提示していただければもう少し具体的な回答ができるかもしれません。
widget11

2021/04/11 20:19

なるほど。 例えばshow.html.erbに<%= javascript_pack_tag 'pages2' %> みたいな形で記載し。 pages2.jsに document.addEventListener('DOMContentLoaded', () => { const pages2 = new Vue({ render: h => h(Page2) }).$mount() document.body.appendChild(pages2.$el)  } ) で、erbファイルでvueコンポーネントを参照できる様にするというイメージですかね? ちょっと勘違いしてるかもしれませんが、、一応追記でapplication.html.erbとjsのファイル構成を記載しておきました。 よろしくお願いします。
widget11

2021/04/11 20:29

すみません!!! おっしゃってる意味が分かった気がします! とりあえず更新や直接urlの対策はできました!!! 色々と教えていただきありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問