質問編集履歴

1

内容の変更

2021/06/17 15:02

投稿

yuu0000
yuu0000

スコア4

test CHANGED
@@ -1 +1 @@
1
- railsにvue.jsを導入したらエラーが起こ
1
+ railsの非同期処理でCouldn't find Upload without an IDと表示され
test CHANGED
@@ -1,16 +1,16 @@
1
- ### railsにvueを導入したらエラーが起こるので解決した
1
+ ### RailsにVue.js使用て非同期処理をさせたい
2
-
3
-
4
-
2
+
3
+
4
+
5
- ``現在Railsアプリケーションにvue.jsをして非同期処理をしているのですが、導入後いくつかエラーが起きてしまっていので原因を解決したくご相談させて頂きました。``
5
+ 現在RailsアプリケーションにVue.jsを用いてお気にり機能の実装をしているのですが、クリック時``ActiveRecord::RecordNotFound (Couldn't find Upload without an ID):``と表示される原因を解決したくご相談させて頂きました。
6
-
7
-
8
-
6
+
7
+
8
+
9
- 具体的な実装としては、vue.jsでお気に入り機能の実装をしており、クリック時にデータベースに保存される機能になります。
9
+ 具体的な実装イメージとしては、クリック時にデータベースにidが保存され、クリック数に応じてカウント数が変動す実装になっております。
10
-
11
-
12
-
13
- 別のユーザーもお気に入りができるようになっており、お気に入り数に総じてカウントが変動する実装をしております。
10
+
11
+
12
+
13
+
14
14
 
15
15
 
16
16
 
@@ -18,71 +18,245 @@
18
18
 
19
19
 
20
20
 
21
- ``ブラウザ起動時のエラー``
21
+ ``クリック時のエラー``
22
-
22
+
23
+
24
+
23
- ```
25
+ ```
24
-
26
+
25
- Uncaught SyntaxError: Cannot use import statement outside a module
27
+ ActiveRecord::RecordNotFound in Api::FavoritesController#create
28
+
29
+ Couldn't find Upload without an ID
30
+
31
+ Extracted source (around line #12):
32
+
33
+ 10
34
+
35
+ 11
36
+
37
+ 12
38
+
39
+ 13
40
+
41
+ 14
42
+
43
+ 15
44
+
45
+
46
+
47
+
48
+
49
+ def create
50
+
51
+ @upload = Upload.find(params[:upload_id])←該当箇所
52
+
53
+ current_user.favorites.create!(favorites_params)
54
+
55
+ head :created
56
+
57
+ end
58
+
59
+ ```
60
+
61
+
62
+
63
+ エラー内容としては、お気に入りをする際に``upload_idがnull``のためにお気に入りの保存ができないようになっているのが現状です。
64
+
65
+
66
+
67
+ 今回は非同期処理で実装を進めているため、投稿内容などが保存されるレイアウトの処理は``componentsディレクトリ``配下にある``FavoriteButton``に記述しております。
68
+
69
+
70
+
71
+ こちらの箇所でupload_idがnullと表示される原因があると考えております。
72
+
73
+
74
+
75
+ ### 該当のソースコード
76
+
77
+
78
+
79
+ ``app/javascript/components/Favorite/FavoriteButton.vue``
80
+
81
+
82
+
83
+ ```vue
84
+
85
+ <template>
86
+
87
+ <div>
88
+
89
+ <div v-if="isFavorited" @click="deleteFavorite()">
90
+
91
+ いいねを取り消す {{ count }}
92
+
93
+ </div>
94
+
95
+ <div v-else @click="registerFavorite()">
96
+
97
+ いいねする {{ count }}
98
+
99
+ </div>
100
+
101
+ </div>
102
+
103
+ </template>
26
104
 
27
105
 
28
106
 
29
107
  <script>
30
108
 
109
+ import axios from 'axios'
110
+
111
+ import { csrfToken } from 'rails-ujs'
112
+
31
- import FavoriteButton from "../../javascript/compenents/Favorite/FavoriteButton";←この部分が該当箇所となっている
113
+ axios.defaults.headers.common['X-CSRF-TOKEN'] = csrfToken()
32
-
33
-
34
-
114
+
115
+
116
+
35
- export default {
117
+ export default {
118
+
36
-
119
+ props: ['userId', 'uploadId'],
120
+
121
+ data() {
122
+
123
+ return {
124
+
37
- components: {FavoriteButton}
125
+ favoriteList: []
38
126
 
39
127
  }
40
128
 
129
+ },
130
+
131
+ computed: {
132
+
133
+ count() {
134
+
135
+ return this.favoriteList.length
136
+
137
+ },
138
+
139
+ isFavorited() {
140
+
141
+ if (this.favoriteList.length === 0) { return false }
142
+
143
+ return Boolean(this.findFavoriteId())
144
+
145
+ }
146
+
147
+ },
148
+
149
+ created: function() {
150
+
151
+ this.fetchFavoriteByUploadId().then(result => {
152
+
153
+ this.favoriteList = result
154
+
155
+ })
156
+
157
+ },
158
+
159
+ methods: {
160
+
161
+ fetchFavoriteByUploadId: async function() {
162
+
163
+ const res = await axios.get(`/api/favorites/?upload_id=${this.uploadId}`)
164
+
165
+ if (res.status !== 200) { process.exit() }
166
+
167
+ return res.data
168
+
169
+ },
170
+
171
+ registerFavorite: async function() {
172
+
173
+ const res = await axios.post('/api/favorites', { upload_id: this.uploadId })
174
+
175
+ if (res.status !== 201) { process.exit() }
176
+
177
+ this.fetchFavoriteByUploadId().then(result => {
178
+
179
+ this.favoriteList = result
180
+
181
+ })
182
+
183
+ },
184
+
185
+ deleteFavorite: async function() {
186
+
187
+ const favoriteId = this.findFavoriteId()
188
+
189
+ const res = await axios.delete(`/api/favorites/${favoriteId}`)
190
+
191
+ if (res.status !== 200) { process.exit() }
192
+
193
+ this.favoriteList = this.favoriteList.filter(n => n.id !== favoriteId)
194
+
195
+ },
196
+
197
+ findFavoriteId: function() {
198
+
199
+ const favorite = this.favoriteList.find((favorite) => {
200
+
201
+ return (favorite.user_id === this.userId)
202
+
203
+ })
204
+
205
+ if (favorite) { return favorite.id }
206
+
207
+ }
208
+
209
+ }
210
+
211
+ }
212
+
41
213
  </script>
42
214
 
43
215
  ```
44
216
 
45
217
 
46
218
 
219
+ ``app/views/uploads/index.html.erb``
220
+
221
+
222
+
223
+ ```erb
224
+
225
+
226
+
227
+ <div id="favorite">
228
+
229
+ ~~省略~~
230
+
231
+ <div class="favorite-content">
232
+
233
+ <% if user_signed_in? %>
234
+
235
+ <favorite-button :user-id="<%= current_user.id %>" :uplaod-id="<%= upload.id %>"></favorite-button>
236
+
47
- ``クリック時のエラー``
237
+ <% end %>
238
+
48
-
239
+ </div>
240
+
49
-
241
+ </div>
50
-
242
+
51
- ```
243
+ ```
52
-
53
- Failed to load resource: the server responded with a status of 500 (Internal Server Error)
244
+
54
-
55
-
56
-
57
- NameError
245
+
58
-
246
+
59
- uninitialized constant ApplicationController::API
247
+ ``app/controllers/api/favorites_controller``
60
-
248
+
249
+
250
+
61
- Did you mean?
251
+ ```controller
62
-
63
- Api
252
+
64
-
65
- Extracted source (around line #5):
253
+ # frozen_string_literal: true
66
-
67
- 3
254
+
68
-
69
- 4
255
+
70
-
71
- 5
72
-
73
- 6
74
-
75
- 7
76
-
77
- 8
78
-
79
-
80
256
 
81
257
  module Api
82
258
 
83
-
84
-
85
- class FavoritesController < ApplicationController::API
259
+ class FavoritesController < ActionController::API
86
260
 
87
261
  before_action :authenticate_user!
88
262
 
@@ -90,445 +264,171 @@
90
264
 
91
265
  def index
92
266
 
93
-
94
-
95
- ```
96
-
97
-
98
-
99
- ```
100
-
101
- [Vue warn]: Error in v-on handler (Promise/async): "Error: Request failed with status code 500"
102
-
103
-
104
-
105
- found in
106
-
107
-
108
-
109
- ---> <FavoriteButton> at app/javascript/compenents/Favorite/FavoriteButton.vue
110
-
111
- <Root>
112
-
113
- ```
114
-
115
-
116
-
117
- ```
118
-
119
- Error: Request failed with status code 500
120
-
121
- at createError (createError.js:17)
122
-
123
- at settle (settle.js:19)
124
-
125
- at XMLHttpRequest.handleLoad (xhr.js:65)
126
-
127
- ```
128
-
129
-
130
-
131
-
132
-
133
- ### 該当のソースコード
134
-
135
-
136
-
137
- **app/javascript/components/Favorite/FavoriteButton.vue**
138
-
139
- ```
140
-
141
- <template>
142
-
143
- <div>
144
-
145
- <div v-if="isFavorited" @click="deleteFavorite()">
146
-
147
- いいねを取り消す {{ count }}
148
-
149
- </div>
150
-
151
- <div v-else @click="registerFavorite()">
152
-
153
- いいねする {{ count }}
154
-
155
- </div>
156
-
157
- </div>
158
-
159
- </template>
160
-
161
-
162
-
163
- <script>
164
-
165
- import axios from 'axios'
166
-
167
- import { csrfToken } from 'rails-ujs'
168
-
169
- axios.defaults.headers.common['X-CSRF-TOKEN'] = csrfToken()
170
-
171
-
172
-
173
- export default {
174
-
175
- props: ['userId', 'uploadId'],
176
-
177
- data() {
178
-
179
- return {
180
-
181
- favoriteList: []
182
-
183
- }
184
-
185
- },
186
-
187
-
188
-
189
- computed: {
190
-
191
- count() {
192
-
193
- return this.favoriteList.length
194
-
195
- },
196
-
197
- isFavorited() {
198
-
199
- if (this.favoriteList.length === 0) { return false }
200
-
201
- return Boolean(this.findFavoriteId())
202
-
203
- }
204
-
205
- },
206
-
207
- created: function() {
208
-
209
- this.fetchFavoriteByUploadId().then(result => {
210
-
211
- this.favoriteList = result
212
-
213
- })
214
-
215
- },
216
-
217
- methods: {
218
-
219
- fetchFavoriteByUploadId: async function() {
220
-
221
- const res = await axios.get(`/api/favorites/?upload_id=${this.uploadId}`)
222
-
223
- if (res.status !== 200) { process.exit() }
224
-
225
- return res.data
226
-
227
- },
228
-
229
- registerFavorite: async function() {
230
-
231
- const res = await axios.post('/api/favorites', { upload_id: this.uploadId })
232
-
233
- if (res.status !== 201) { process.exit() }
234
-
235
- this.fetchFavoriteByUploadId().then(result => {
236
-
237
- this.favoriteList = result
238
-
239
- })
240
-
241
- },
242
-
243
- deleteFavorite: async function() {
244
-
245
- const favoriteId = this.findFavoriteId()
246
-
247
- const res = await axios.delete(`/api/favorites/${favoriteId}`)
248
-
249
- if (res.status !== 200) { process.exit() }
250
-
251
- this.favoriteList = this.favoriteList.filter(n => n.id !== favoriteId)
252
-
253
- },
254
-
255
- findFavoriteId: function() {
256
-
257
- const favorite = this.favoriteList.find((favorite) => {
258
-
259
- return (favorite.user_id === this.userId)
260
-
261
- })
262
-
263
- if (favorite) { return favorite.id }
264
-
265
- }
266
-
267
- }
267
+ render json: Favorite.filter_by_upload(params[:upload_id]).select(:id, :user_id, :upload_id)
268
+
269
+ end
270
+
271
+
272
+
273
+ def create
274
+
275
+ @upload = Upload.find(params[:upload_id])
276
+
277
+ current_user.favorites.create!(favorites_params)
278
+
279
+ head :created
280
+
281
+ end
282
+
283
+
284
+
285
+ def destroy
286
+
287
+ current_user.favorites.find(params[:id]).destroy!
288
+
289
+ head :ok
290
+
291
+ end
292
+
293
+
294
+
295
+ private
296
+
297
+
298
+
299
+ def favorites_params
300
+
301
+ params.require(:favorite).permit(:upload_id)
302
+
303
+ end
304
+
305
+ end
306
+
307
+ end
308
+
309
+ ```
310
+
311
+
312
+
313
+ ``app/models/favorite.rb``
314
+
315
+
316
+
317
+ ```model
318
+
319
+ # frozen_string_literal: true
320
+
321
+
322
+
323
+ class Favorite < ApplicationRecord
324
+
325
+ belongs_to :user
326
+
327
+ belongs_to :upload
328
+
329
+
330
+
331
+ validates :user_id, presence: true
332
+
333
+ validates :upload_id, presence: true
334
+
335
+
336
+
337
+ scope :filter_by_upload, ->(upload_id) { where(upload_id: upload_id) if upload_id }
338
+
339
+ end
340
+
341
+
342
+
343
+ ```
344
+
345
+
346
+
347
+ ``/config/routes``
348
+
349
+
350
+
351
+ ```
352
+
353
+ # frozen_string_literal: true
354
+
355
+
356
+
357
+ Rails.application.routes.draw do
358
+
359
+ namespace :api, { format: 'json' } do
360
+
361
+ resources :favorites, only: [:index, :create, :destroy]
362
+
363
+ end
364
+
365
+
366
+
367
+ devise_for :users
368
+
369
+ get 'uploads/index'
370
+
371
+ root to: "uploads#index"
372
+
373
+ resources :uploads do
374
+
375
+ resource :favorites, only: [:create, :destroy]
376
+
377
+ end
378
+
379
+
380
+
381
+ resources :users, only: [:show, :edit, :update]
382
+
383
+
384
+
385
+ end
386
+
387
+
388
+
389
+ ```
390
+
391
+
392
+
393
+ ### 試したこと
394
+
395
+
396
+
397
+ **・favorites_controllerに``@upload = Upload.find(params[upload_id])``と記述してupload_idを取得できるようにしてみましたが、エラーは変わらずidがnullと表示されたままでした。**
398
+
399
+
400
+
401
+ **・ルーティングに原因がある可能性を考え、
402
+
403
+ ``resources :uploads do
404
+
405
+ resource :favorites, only: [:create, :destroy]
406
+
407
+ end``
408
+
409
+ と記述してuploadのルーティングにネストして記述しましたが、こちらもエラー解決にはなりませんでした。**
410
+
411
+
412
+
413
+ **・Vue.jsのファイルで、apiが想定しているparamsに対して異なる値があるために正常に処理されない可能性があると考えておりますが、どの部分を修正すればいいのか分からない状態です。**
414
+
415
+
416
+
417
+ ```
418
+
419
+ const res = await axios.post('/api/favorites', { upload_id: this.uploadId })
420
+
421
+
422
+
423
+ {
424
+
425
+  favorite: { upload_id: 実際の値 }
268
426
 
269
427
  }
270
428
 
271
- </script>
429
+ ==こちらにparamsとして処理される値が、apiが想定している値とは違うものが送られている可能性がある
272
-
430
+
273
- ```
431
+ ```
274
-
275
-
276
-
277
- **app/javascript/packs/index.js**
278
-
279
-
280
-
281
- ```
282
-
283
- import 'babel-polyfill'
284
-
285
- import Vue from 'vue'
286
-
287
-
288
-
289
- // 作成したコンポーネントファイルをimportします
290
-
291
- import FavoriteButton from '../compenents/Favorite/FavoriteButton.vue'
292
-
293
-
294
-
295
- document.addEventListener('DOMContentLoaded', () => {
296
-
297
- new Vue({
298
-
299
- el: '#favorite',
300
-
301
- components: { FavoriteButton }
302
-
303
- })
304
-
305
- })
306
-
307
- ```
308
-
309
-
310
-
311
- **app/controllers/api/favorites_controller**
312
-
313
-
314
-
315
- ```
316
-
317
- # frozen_string_literal: true
318
-
319
-
320
-
321
- module Api
322
-
323
-
324
-
325
- class FavoritesController < ApplicationController::API
326
-
327
- before_action :authenticate_user!
328
-
329
-
330
-
331
- def index
332
-
333
- render json: Favorite.filter_by_upload(params[:id]).select(:id, :user_id, :upload_id)
334
-
335
- end
336
-
337
-
338
-
339
- def create
340
-
341
- current_user.favorites.create!(favorites_params)
342
-
343
- head :created
344
-
345
- end
346
-
347
-
348
-
349
- def destroy
350
-
351
- current_user.favorites.find(params[:id]).destroy
352
-
353
- head :ok
354
-
355
- end
356
-
357
-
358
-
359
- private
360
-
361
-
362
-
363
- def favorites_params
364
-
365
- params.require(:favorite).permit(:upload_id)
366
-
367
- end
368
-
369
- end
370
-
371
- end
372
-
373
- ```
374
-
375
-
376
-
377
- **app/models/favorite.rb**
378
-
379
-
380
-
381
- ```
382
-
383
- class Favorite < ApplicationRecord
384
-
385
- belongs_to :user
386
-
387
- belongs_to :upload
388
-
389
-
390
-
391
- scope :filter_by_upload, ->(upload_id) {where(upload_id: upload_id) if upload_id }
392
-
393
- end
394
-
395
- ```
396
-
397
-
398
-
399
- **app/config/routes**
400
-
401
-
402
-
403
- ```
404
-
405
- Rails.application.routes.draw do
406
-
407
- namespace :api, { format: 'json' } do
408
-
409
- resources :favorites, only: [:index, :create, :destroy]
410
-
411
- end
412
-
413
-
414
-
415
- devise_for :users
416
-
417
- get 'uploads/index'
418
-
419
- root to: "uploads#index"
420
-
421
- resources :uploads
422
-
423
- resources :users, only: [:show, :edit, :update]
424
-
425
-
426
-
427
- end
428
-
429
- ```
430
-
431
-
432
-
433
- **config/webpack/developement.js**
434
-
435
-
436
-
437
- ```
438
-
439
- process.env.NODE_ENV = process.env.NODE_ENV || 'development'
440
-
441
-
442
-
443
- const environment = require('./environment')
444
-
445
-
446
-
447
- module.exports = Object.assign({}, environment.toWebpackConfig(), {
448
-
449
- resolve: {
450
-
451
- alias: {
452
-
453
- 'vue$': 'vue/dist/vue.esm.js'
454
-
455
- }
456
-
457
- }
458
-
459
- })
460
-
461
- ```
462
-
463
-
464
-
465
- **app/views/uploads/index.html.erb**
466
-
467
-
468
-
469
- ```
470
-
471
- <%= javascript_pack_tag 'index' %>
472
-
473
-
474
-
475
- ~~省略
476
-
477
- <div class="favorite-content">
478
-
479
- <div id="favorite">
480
-
481
- <% if user_signed_in? %>
482
-
483
- <favorite-button :user-id="<%= current_user.id %>" :uplaod-id="<%= upload.id %>"></favorite-button>
484
-
485
- <% end %>
486
-
487
- </div>
488
-
489
- </div>
490
-
491
- ```
492
-
493
-
494
-
495
- ### 試したこと
496
-
497
-
498
-
499
- **vue.jsの導入方法は下記の通りです。**
500
-
501
-
502
-
503
- ``$bundle exec rails webpacker:install:vue``
504
-
505
- ``$yarn add axios rails-ujs``
506
-
507
- 上記の実行後に**developement.js**の編集を行いました。
508
-
509
-
510
-
511
- **コードの確認**
512
-
513
-
514
-
515
- index.jsファイルで、``import FavoriteButton from '../compenents/Favorite/FavoriteButton.vue'``と末尾に.vueをファイルと同名になるように記述してみたがエラーが変わらず表示されてしまう。
516
-
517
-
518
-
519
- ```api
520
-
521
- module Api
522
-
523
-
524
-
525
- end
526
-
527
- ```
528
-
529
- と記述して``ApplicationController::API``を継承するようにしているがエラー表示の解決には至りませんでした。
530
-
531
-
532
432
 
533
433
 
534
434
 
@@ -536,18 +436,10 @@
536
436
 
537
437
 
538
438
 
539
- **開発環境**
439
+ ``開発環境``
540
440
 
541
441
  ・rubymine
542
442
 
543
443
  ・ruby(3.0.1)
544
444
 
545
445
  ・Ruby on rails (6.1.3.1)
546
-
547
- ・gem 'webpacker', '~> 5.0'
548
-
549
-
550
-
551
- Githubのリポジトリ
552
-
553
- [github](https://github.com/yuuffff1212/locat)