前提・実現したいこと
vueを使い非同期通信でフォロー機能を追加したいです。
既にフォロー機能は実装できているので、フォローボタンのみvueで非同期通信に書き換えたいです。
発生している問題・エラーメッセージ
axiosを使い、postを実行したところ404エラーが出ました。
//エラーログ web_1 | Processing by Api::V1::RelationshipsController#create as JSON web_1 | Parameters: {"followed_id"=>1, "relationship"=>{"followed_id"=>1}} web_1 | User Load (0.4ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 ORDER BY `users`.`id` ASC LIMIT 1 web_1 | ↳ /usr/local/bundle/gems/activerecord-5.2.6/lib/active_record/log_subscriber.rb:98 web_1 | (0.2ms) BEGIN web_1 | ↳ app/models/user.rb:26 web_1 | User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1 web_1 | ↳ app/models/user.rb:26 web_1 | (0.3ms) ROLLBACK web_1 | ↳ app/models/user.rb:26 web_1 | Completed 201 Created in 8ms (ActiveRecord: 1.1ms) web_1 | web_1 | web_1 | Started GET "/api/v1/relationships/?followed_id=1" for 172.24.0.1 at 2021-09-11 09:46:32 +0000 web_1 | Cannot render console from 172.24.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 web_1 | web_1 | ActionController::RoutingError (No route matches [GET] "/api/v1/relationships"): web_1 | web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:65:in `call' web_1 | web-console (3.7.0) lib/web_console/middleware.rb:135:in `call_app' web_1 | web-console (3.7.0) lib/web_console/middleware.rb:22:in `block in call' web_1 | web-console (3.7.0) lib/web_console/middleware.rb:20:in `catch' web_1 | web-console (3.7.0) lib/web_console/middleware.rb:20:in `call' web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/show_exceptions.rb:33:in `call' web_1 | railties (5.2.6) lib/rails/rack/logger.rb:38:in `call_app' web_1 | railties (5.2.6) lib/rails/rack/logger.rb:26:in `block in call' web_1 | activesupport (5.2.6) lib/active_support/tagged_logging.rb:71:in `block in tagged' web_1 | activesupport (5.2.6) lib/active_support/tagged_logging.rb:28:in `tagged' web_1 | activesupport (5.2.6) lib/active_support/tagged_logging.rb:71:in `tagged' web_1 | railties (5.2.6) lib/rails/rack/logger.rb:26:in `call' web_1 | sprockets-rails (3.2.2) lib/sprockets/rails/quiet_assets.rb:13:in `call' web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/remote_ip.rb:81:in `call' web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/request_id.rb:27:in `call' web_1 | rack (2.2.3) lib/rack/method_override.rb:24:in `call' web_1 | rack (2.2.3) lib/rack/runtime.rb:22:in `call' web_1 | activesupport (5.2.6) lib/active_support/cache/strategy/local_cache_middleware.rb:29:in `call' web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/executor.rb:14:in `call' web_1 | actionpack (5.2.6) lib/action_dispatch/middleware/static.rb:127:in `call' web_1 | rack (2.2.3) lib/rack/sendfile.rb:110:in `call' web_1 | webpacker (5.4.2) lib/webpacker/dev_server_proxy.rb:25:in `perform_request' web_1 | rack-proxy (0.7.0) lib/rack/proxy.rb:63:in `call' web_1 | railties (5.2.6) lib/rails/engine.rb:524:in `call' web_1 | puma (3.12.6) lib/puma/configuration.rb:227:in `call' web_1 | puma (3.12.6) lib/puma/server.rb:706:in `handle_request' web_1 | puma (3.12.6) lib/puma/server.rb:476:in `process_client' web_1 | puma (3.12.6) lib/puma/server.rb:334:in `block in run' web_1 | puma (3.12.6) lib/puma/thread_pool.rb:135:in `block in spawn_thread'
cocnsole
1xhr.js:184 GET http://localhost:3000/api/v1/relationships/?followed_id=1 404 (Not Found) 2 3createError.js:17 Uncaught (in promise) Error: Request failed with status code 404 4 at createError (createError.js:17) 5 at settle (settle.js:19) 6 at XMLHttpRequest.onloadend (xhr.js:58)
該当のソースコード
//routes.rb Rails.application.routes.draw do devise_for :admins, controllers: { sessions: 'admins/sessions', passwords: 'admins/passwords', registrations: 'admins/registrations', } devise_for :users, controllers: { sessions: 'users/sessions', passwords: 'users/passwords', registrations: 'users/registrations', } devise_scope :user do post 'users/guest_sign_in', to: 'users/sessions#guest_sign_in' end # 追記 namespace :api do namespace :v1, format: 'json' do resources :relationships, only: [:create, :destroy] end end # ========= ユーザー(public)のルーティング ================ scope module: :public do root to: 'camps#index' get '/about' => 'homes#about' resources :users, only: [:index, :show, :edit, :update] do resource :relationships, only: [:create, :destroy] resources :reservations, only: [:index, :show] member do get 'following' get 'followers' get 'favorites' get 'post' end end end
//follows.html.erb <%= javascript_pack_tag 'relationship' %> <%= link_to "#{user.followings.count} フォロー", following_user_path(user), class: "link-color" %><span> | </span> <%= link_to "#{user.followers.count} フォロワー ", followers_user_path(user), class: "link-color" %> <div id="relationship"> <% if current_user.id != user.id %> <Relationship-button :follower-id="<%= current_user.id %>" :followed-id="<%= @user.id %>"></Relationship-button> <% end %> </div>
//RelationshipButton.vue <template> <div> <div v-if="isRelationshiped" @click="deleteRelationship()" class="btn btn-bg follow-followed"> <i class="fas fa-user-minus"></i> フォロー解除 </div> <div v-else @click="registerRelationship()" class="btn btn-bg" style="margin:0;"> <i class="fas fa-user-plus"></i> フォローする </div> </div> </template> <script> import axios from 'axios' import { csrfToken } from 'rails-ujs' axios.defaults.headers.common['X-CSRF-TOKEN'] = csrfToken() export default { props: ['followerId', 'followedId'], data() { return { relationshipList: [] } }, computed: { count() { return this.relationshipList.length }, isRelationshiped() { if (this.relationshipList.length === 0) { return false } return Boolean(this.findRelationshipId()) } }, created: function() { this.fetchRelationshipByFollowedId().then(result => { this.relationshipList = result }) }, methods: { fetchRelationshipByFollowedId: async function() { const res = await axios.get(`/api/v1/relationships/?followed_id=${this.followedId}`) if (res.status !== 200) { process.exit() } return res.data }, registerRelationship: async function() { const res = await axios.post('/api/v1/relationships', { followed_id: this.followedId }) if (res.status !== 201) { process.exit() } this.fetchRelationshipByFollowedId().then(result => { this.relationshipList = result }) }, deleteRelationship: async function() { const relationshipId = this.findRelationshipId() const res = await axios.delete(`/api/v1/relationships/${relationshipId}`) if (res.status !== 200) { process.exit() } this.relationshipList = this.relationshipList.filter(n => n.id !== relationshipId) }, findRelationshipId: function() { const relationship = this.relationshipList.find((relationship) => { return (relationship.follower_id === this.followerId) }) if (relationship) { return relationship.id } } } } </script>
//RelationshipsController module Api module v1 class RelationshipsController < ActionController::API before_action :authenticate_user! def create current_user.follow(relationships_params) head :created end def destroy current_user.unfollow(params[:user_id]) head :ok end private def relationships_params params.require(:relationship).permit(:user_id, :followed_id) end end end end
試したこと
rails routesでパスの確認
api_v1_relationships POST /api/v1/relationships(.:format) api/v1/relationships#create {:format=>/json/} api_v1_relationship DELETE /api/v1/relationships/:id(.:format) api/v1/relationships#destroy {:format=>/json/}
baseurlの設定
//vue.config.js module.exports = { // ベースURLの設定 baseUrl: 'http://localhost:3000/', publicPath: "/" }
補足情報(FW/ツールのバージョンなど)
windows10 home
Ruby 2.6.3
Ruby on Rails 5.2.6
解決に繋がるヒントを頂けますと幸いです。
よろしくお願いいたします。
rails のログはどうなっていますか?
ご返信ありがとうございます。
エラーログとルーティングを追記いたしました。
RelationshipsController の module v1 が小文字になってますね。
それで uninitialized constant Api::V1::RelationshipsController になってるのかもしれません。
V1 にしてみてください。
大文字に直してみましたが特に変化ありませんでした。
こちらコントローラーのみ大文字にした方がいいということでしょうか。
module や class の名前は定数(先頭が大文字)の必要があります。
RelationshipsController のパスは app/controllers/api/v1/relationships_controller.rb ですか?
ありがとうございます。
RelationshipsController のパスは app/controllers/api/v1/relationships.controller.rb で _がありません。
コントローラー名に_をつけて修正したところエラーメッセージが変わったので追記しました。
フォローボタンを押すとpostメソッドになるはずが、なぜかエラーログがgetに変わりました。
POST のあとに vue の registerRelationship の中で
fetchRelationshipByFollowedId を呼んでいるので、そのリクエストだと思います。
ありがとうございます。
現状、パスの確認を行ってみましたが原因が特定できておりません、
他にエラーの原因として考えられるものをご教授いただけますでしょうか。
ActionController::RoutingError (No route matches [GET] "/api/v1/relationships"):
GET /api/v1/relationships は定義されていません。定義するかリクエストを削除します。
定義する場合
routes.rb
resources :relationships, only: [:index, :create, :destroy]
relationships_controller.rb
class RelationshipsController < ActionController::API
def index
# 内容を記述
end
リクエストを削除する場合
RelationshipButton.vue
registerRelationship: async function() {
const res = await axios.post('/api/v1/relationships', { followed_id: this.followedId })
if (res.status !== 201) { process.exit() }
// ここから下は不要
// this.fetchRelationshipByFollowedId().then(result => {
// this.relationshipList = result
// })
},
ありがとうございます。
indexをルーティングとコントローラーに定義したら無事にエラーが解決できました。
まだ別のエラーが出ていますが、まずは自分でやってみたいと思います。
度々すみません。
ベストアンサーにさせていただきたいのですが、調べてもベストアンサーボタンがあるとの事ですが
僕の画面に見当たらず、お伺いしてもよろしいでしょうか。
ボタンは"質問への追記・修正"では表示されず、"回答"しないと表示されないのだと思います。
今は多分どこかにあります。
回答後、表示されました。
最後までご丁寧にありがとうございました。
回答1件
あなたの回答
tips
プレビュー