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

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

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

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

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回答

729閲覧

【Rails×Vue】レビュー機能を実装したいのですが、404エラーが表示されてしまいます

fujitopro

総合スコア1

Vue.js

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

SPA(Single-page Application)

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

Ruby on Rails 6

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

0グッド

0クリップ

投稿2021/05/02 01:02

編集2021/05/02 05:20

商品をレビューできるようにしたいです

Rails×VueでSPA化されたサイトを作っているのですが
商品をレビューする機能を実装した際に、以下のようなエラーが発生しています

発生している問題・エラーメッセージ

createError.js:17 Uncaught (in promise) Error: Request failed with status code 404

該当のソースコード

Vue

1(DogfoodProductPage.vue) 2<template> 3<div class="top_contents"> 4<h2>詳細ページ</h2> 5<table> 6 <tbody> 7 <tr> 8 <th>登録ID</th> 9 <td>{{ dogfood.id }}</td> 10 </tr> 11 <tr> 12 <th>商品名</th> 13 <td>{{ dogfood.name }}</td> 14 </tr> 15 <tr> 16 <th>タンパク量</th> 17 <td>{{ dogfood.protein }}</td> 18 </tr> 19 <tr> 20 <th>脂肪量</th> 21 <td>{{ dogfood.fal }}</td> 22 </tr> 23 <tr> 24 <th>価格</th> 25 <td>{{ dogfood.price }}</td> 26 </tr> 27 </tbody> 28</table> 29 30<form @submit.prevent="createReview"> 31 <div> 32 <label>本文</label> 33 <input type='textarea' v-model='review.body'> 34 </div> 35 36 <button type="submit">コメント送信</button> 37</form> 38 39<ul> 40 <li v-for="review in reviews"> 41 {{ review.body }} 42 </li> 43</ul> 44 45 46</div> 47</template> 48 49<script> 50import axios from 'axios'; 51axios.defaults.headers.common = { 52 'X-Requested-With': 'XMLHttpRequest', 53 'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content') 54}; 55 56export default { 57 data: function () { 58 return { 59 review: { 60 body: '' 61 }, 62 reviews: [], 63 dogfood: [], 64 } 65 }, 66 methods: { 67 createReview: function() { 68 axios 69 .post('/api/v1/reviews', this.review) 70 .then(response => (this.info = response)) 71 }, 72 getReviews: function() { 73 axios 74 .get('/api/v1/reviews.json') 75 .then(response => { 76 for(var i = 0; i < response.data.reviews.length; i++) { 77 this.reviews.push(response.data.reviews[i]) 78 } 79 }) 80 } 81 }, 82 mounted : function() { 83 axios 84 .get(`/api/v1/sdogfoods/${this.$route.params.id}.json`) 85 .then(response => (this.dogfood = response.data)) 86 .catch(error => { 87 console.error(error); 88 if (error.response.data && error.response.data.errors) { 89 this.errors = error.response.data.errors; 90 } 91 }); 92 this.getReviews() 93 } 94} 95</script> 96 97<style scoped> 98</style>

Rails

1(reviews.controller) 2class Api::V1::ReviewsController < ApiController 3 4 def index 5 dogfood = Dogfood.find(params[:dogfood_id]) 6 reviews = dogfood.reviews.order('created_at DESC') 7 render json: reviews 8 end 9 10 def create 11 @review = Review.new(review_params) 12 if @review.save 13 render :index, status: :created 14 else 15 render json: @review.errors, status: :unprocessable_entity 16 end 17 end 18 19 private 20 21 def review_params 22 params.require(:review).permit(:dogfood_id, :body) 23 end 24end

rails

1(sdogfood_controller.rb) 2class Api::V1::SdogfoodsController < ApiController 3 before_action :set_dogfood, only: [:show] 4 5 def index 6 dogfoods = Dogfood.select(:id, :name, :protein, :fal, :price) 7 render json: dogfoods 8 end 9 10 def show 11 render json: @dogfood 12 end 13 14 private 15 16 def set_dogfood 17 @dogfood = Dogfood.find(params[:id]) 18 end 19end

Rails

1(review.rb) 2class Review < ApplicationRecord 3 belongs_to :dogfood 4end

Rails

1(dogfood.rb) 2class Dogfood < ApplicationRecord 3 has_many :reviews 4end
(route.rb) Rails.application.routes.draw do root to: 'home#index' (省略) namespace :api, {format: 'json'} do namespace :v1 do resources :sdogfoods, only: [:index, :show] resources :reviews, except: [:update] end end end

試したこと

this.getReviews()のコードを消せばエラーは消えるので、現在表示されているエラーは、getReviewsのaxiosが原因だと考えています。

(追記)
reviews.contorollerの、以下のコードに問題があると判明しました。

def index dogfood = Dogfood.find(params[:dogfood_id]) (省略) end

params[:dogfood_id]で、IDを取得できていないのでエラーが発生していたようです。

ならばと思い、(sdogfood_controller.rb)のshowアクションを、以下のように変更してみたのですが、render jsonを2つ記載すると、元々のrender json: @dogfoodが機能しなくなってしまい、別の問題で悩んでいます。

rails

1(sdogfood_controller.rb) 2class Api::V1::SdogfoodsController < ApiController 3 before_action :set_dogfood, only: [:show] 4 5 def index 6 dogfoods = Dogfood.select(:id, :name, :protein, :fal, :price) 7 render json: dogfoods 8 end 9 10 def show 11 @reviews = @dogfood.reviews.order('created_at DESC') 12 render json: @dogfood 13 render json: @reviews 14 end 15 16 private 17 18 def set_dogfood 19 @dogfood = Dogfood.find(params[:id]) 20 end 21end

現在は、問題を解決するために

  • review_controller内で、dogfoodのIDを入手する
  • render jsonを複数遅れるようにする

上記の方法のどちらかで、上手くいく方法がないか調べているところです。

もし、何か分かる方がいましたら、アドバイスをいただけると助かります。

※createReviewも、送信したら以下のエラーが出ますが、まずgetReviesのエラーを解決しようと思い、一旦createReviewは放置している状態です
Uncaught (in promise) Error: Request failed with status code 422

補足情報

Rails 6.0.3.5

上記のコードは、以下のようなコードで表示させています。

Rails

1(index.erb.html) 2<% provide(:title, "ドッグフードナビ") %> 3<%= javascript_pack_tag 'hello_vue' %>

JavaScript

1(hello_vue.js) 2import Vue from 'vue' 3import App from '../app.vue' 4 5document.addEventListener('DOMContentLoaded', () => { 6 const el = document.body.appendChild(document.createElement('hello')) 7 const app = new Vue({ 8 el, 9 render: h => h(App) 10 }) 11})

Vue

1(app.vue) 2<template> 3 <div> 4 <router-view></router-view> 5 </div> 6</template> 7 8<script> 9import Vue from 'vue' 10import VueRouter from 'vue-router' 11 12import DogfoodTopPage from 'DogfoodTopPage.vue' 13import DogfoodProductPage from 'DogfoodProductPage.vue' 14 15const router = new VueRouter({ 16 mode: 'history', 17 base: process.env.BASE_URL, 18 routes: [ 19 { path: '/', 20 component: DogfoodTopPage }, 21 { path: '/sdogfoods/:id(\d+)', 22 name: 'DogfoodProductPage', 23 component: DogfoodProductPage } 24 ] 25}) 26 27Vue.use(VueRouter) 28 29export default { 30 router 31} 32</script> 33 34<style scoped> 35</style>

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

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

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

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

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

guest

回答1

0

自己解決

上記の問題ですが、axiosの.getの第二引数にparamsを指定することで解決しました。

vue

1(DogfoodProductPage.vue) 2<template> 3<div class="top_contents"> 4<h2>詳細ページ</h2> 5<table> 6 <tbody> 7 <tr> 8 <th>登録ID</th> 9 <td>{{ dogfood.id }}</td> 10 </tr> 11 <tr> 12 <th>商品名</th> 13 <td>{{ dogfood.name }}</td> 14 </tr> 15 <tr> 16 <th>タンパク量</th> 17 <td>{{ dogfood.protein }}</td> 18 </tr> 19 <tr> 20 <th>脂肪量</th> 21 <td>{{ dogfood.fal }}</td> 22 </tr> 23 <tr> 24 <th>価格</th> 25 <td>{{ dogfood.price }}</td> 26 </tr> 27 </tbody> 28</table> 29 30<form @submit.prevent="createReview"> 31 <input type='textarea' v-model='review.body'> 32 33 <button type="submit">コメント送信</button> 34</form> 35 36<ul> 37 <li v-for="review in reviews"> 38 {{ review.body }} 39 </li> 40</ul> 41 42 43</div> 44</template> 45 46<script> 47import axios from 'axios'; 48axios.defaults.headers.common = { 49 'X-Requested-With': 'XMLHttpRequest', 50 'X-CSRF-TOKEN' : document.querySelector('meta[name="csrf-token"]').getAttribute('content') 51}; 52 53export default { 54 data: function () { 55 return { 56 review: { 57 body: '' 58 }, 59 reviews: [], 60 dogfood: [] 61 } 62 }, 63 methods: { 64 createReview: function() { 65 axios 66 .post('/api/v1/reviews', this.review) 67 .then(response => (this.info = response)) 68 }, 69 getReviews: function() { 70 axios 71 .get('/api/v1/reviews.json', { 72 params: { 73 dogfood_id: this.$route.params.id 74 } 75 }) 76 .then(response => (this.reviews = response.data)) 77 } 78 }, 79 mounted : function() { 80 axios 81 .get(`/api/v1/sdogfoods/${this.$route.params.id}.json`) 82 .then(response => (this.dogfood = response.data)) 83 .catch(error => { 84 console.error(error); 85 if (error.response.data && error.response.data.errors) { 86 this.errors = error.response.data.errors; 87 } 88 }); 89 this.getReviews() 90 } 91} 92</script> 93 94<style scoped> 95</style>

rails

1(reviews_controller.rb) 2class Api::V1::ReviewsController < ApiController 3 4 def index 5 dogfood = Dogfood.find(params[:dogfood_id]) 6 reviews = dogfood.reviews.order('created_at DESC') 7 render json: reviews 8 end 9 10 def create 11 @review = Review.new(review_params) 12 if @review.save 13 render :index, status: :created 14 else 15 render json: @review.errors, status: :unprocessable_entity 16 end 17 end 18 19 private 20 21 def review_params 22 params.require(:review).permit(:dogfood_id, :body) 23 end 24end

このようなコードにすることで、reviewsコントローラが対象のドッグフードを見つけることができるので、レビューを表示させることが出来ました。

投稿2021/05/02 13:20

fujitopro

総合スコア1

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.47%

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

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

質問する

関連した質問