前提・実現したいこと
現在PHP、Laravelで記事を投稿するページを作っています。
記事のハートをクリックするといいね数がカウントされて、ハートが赤くなるようにしたいです。
ハートを押してもいいね数がカウントされずエラーが出ています。
発生している問題・エラーメッセージ
Laravel.logのエラーです
Laravel
1[2021-10-03 17:19:24] local.ERROR: SQLSTATE[23502]: Not null violation: 7 2ERROR: null value in column "record_id" violates not-null constraint 3DETAIL: Failing row contains (27, 2, null, 2021-10-03 17:19:24, 2021-10-03 17:19:24). (SQL: insert into "likes" ("created_at", "record_id", "updated_at", "user_id") values (2021-10-03 17:19:24, ?, 2021-10-03 17:19:24, 2)) {"userId":2,"exception":"[object] (Illuminate\Database\QueryException(code: 23502): SQLSTATE[23502]: Not null violation: 7 ERROR: null value in column \"record_id\" violates not-null constraint
いいね数をカウントしているlikesテーブルに登録する際に、record_idがnullになっていて、DBに登録できないようです。
record_idが何故nullになるのか分からず、ご助言いただければと思います。
よろしくお願いいたします。
該当のソースコード
likesテーブル
php
1<?php 2//省略 3 public function up() 4 { 5 Schema::create('likes', function (Blueprint $table) { 6 $table->bigIncrements('id'); 7 $table->bigInteger('user_id'); 8 $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); 9 $table->bigInteger('record_id'); 10 $table->foreign('record_id')->references('id')->on('records')->onDelete('cascade'); 11 $table->timestamps(); 12 }); 13 } 14
PostController.php
php
1<?php 2 3namespace App\Http\Controllers; 4 5use Illuminate\Http\Request; 6use App\Record; 7 8class PostController extends Controller 9{ 10 11 //一覧表示処理 12 public function index() 13 { 14 $posts = Record::all()->sortByDesc('created_at'); 15 return view('post.post_index', ['posts' => $posts]); 16 } 17 18 //投稿画面表示 19 public function create() 20 { 21 return view('post.post_create'); 22 } 23 24 //投稿処理 25 public function store(Request $request) 26 { 27 $post = new Record; 28 $post->memo = $request->body; 29 $post->user_id = $request->user()->id; 30 $post->save(); 31 return redirect()->route('post.index'); 32 33 } 34 35 //個別表示 36 public function show() 37 { 38 } 39 40 //編集画面表示 41 public function edit($id) 42 { 43 $post = Record::find($id); 44 return view('post.post_edit',['post' => $post]); 45 } 46 47 //編集処理 48 public function update(Request $request,$id) 49 { 50 $update = ['memo' => $request->memo ]; 51 Record::where('id',$id)->update($update); 52 return redirect()->route('post.index'); 53 } 54 55 //削除処理 56 public function destroy($id) 57 { 58 Record::where('id', $id)->delete(); 59 return redirect()->route('post.index'); 60 } 61 62 //いいね処理 63 //いいねが表示されない record_idがnullになる 64 public function like(Request $request,Record $record) 65 { 66 $record->likes()->detach($request->user()->id); 67 $record->likes()->attach($request->user()->id); 68 69 return [ 70 'id' => $record->id, 71 'countLikes' => $record->count_likes, 72 ]; 73 } 74 75 //いいね解除処理 76 public function unlike(Request $request,Record $record) 77 { 78 $record->likes()->detach($request->user()->id); 79 80 return [ 81 'id' => $record->id, 82 'countLikes' => $record->count_likes, 83 ]; 84 } 85} 86
Record.php
php
1<?php 2 3namespace App; 4 5use Illuminate\Database\Eloquent\Model; 6use Illuminate\Database\Eloquent\Relations\BelongsTo; 7use Illuminate\Database\Eloquent\Relations\BelongsToMany; 8 9class Record extends Model 10{ 11 protected $fillable = [ 12 'memo', 13 ]; 14 15 public function user(): BelongsTo 16 { 17 return $this->belongsTo('App\User'); 18 } 19 20 public function likes(): BelongsToMany 21 { 22 return $this->belongsToMany('App\User', 'likes')->withTimestamps(); 23 } 24 25 public function isLikedBy(?User $user): bool 26 { 27 return $user 28 ? (bool)$this->likes->where('id', $user->id)->count() 29 : false; 30 } 31 32 public function getCountLikesAttribute(): int 33 { 34 return $this->likes->count(); 35 } 36} 37
PostLike.vue
vue
1<template> 2 <div> 3 <button 4 type="button" 5 class="btn m-0 p-1 shadow-none" 6 > 7 <i class="fas fa-heart mr-1" 8 :class="{'red-text':this.isLikedBy, 'animated heartBeat fast':this.gotToLike}" 9 @click="clickLike" 10 /> 11 </button> 12 {{ countLikes }} 13 </div> 14</template> 15 16<script> 17 export default { 18 props: { 19 initialIsLikedBy: { 20 type: Boolean, 21 default: false, 22 }, 23 initialCountLikes: { 24 type: Number, 25 default: 0, 26 }, 27 authorized: { 28 type: Boolean, 29 default: false, 30 }, 31 endpoint: { 32 type: String, 33 }, 34 }, 35 data() { 36 return { 37 isLikedBy: this.initialIsLikedBy, 38 countLikes: this.initialCountLikes, 39 gotToLike: false, 40 } 41 }, 42 methods: { 43 clickLike() { 44 if (!this.authorized) { 45 alert('いいね機能はログイン中のみ使用できます') 46 return 47 } 48 this.isLikedBy 49 ? this.unlike() 50 : this.like() 51 }, 52 async like() { 53 const response = await axios.put(this.endpoint) 54 this.isLikedBy = true 55 this.countLikes = response.data.countLikes 56 this.gotToLike = true 57 }, 58 async unlike() { 59 const response = await axios.delete(this.endpoint) 60 this.isLikedBy = false 61 this.countLikes = response.data.countLikes 62 this.gotToLike = false 63 }, 64 }, 65 } 66</script> 67
php
1@extends('app') 2 3@section('title','studyaid | みんなの投稿') 4 5@section('content') 6@include('nav') 7<div class="container"> 8 @foreach($posts as $post) 9 <div class="card mt-3"> 10 <div class="card-body d-flex flex-row"> 11 <i class="fas fa-user-circle fa-3x mr-1"></i> 12 <div> 13 <div class="font-weight-bold"> 14 {{ $post->user->getData() }} 15 </div> 16 <div class="font-weight-lighter"> 17 {{ $post->created_at->format('Y/m/d H:i') }} 18 </div> 19 </div> 20 21 @if( Auth::id() === $post->user_id ) 22 <!-- dropdown --> 23 <div class="ml-auto card-text"> 24 <div class="dropdown"> 25 <a data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 26 <button type="button" class="btn btn-link text-muted m-0 p-2"> 27 <i class="fas fa-ellipsis-v"></i> 28 </button></a> 29 30 <div class="dropdown-menu dropdown-menu-right"> 31 <a class="dropdown-item" href="{{ route('post.edit', ['post' => $post]) }}"> 32 <i class="fas fa-pen mr-1"></i>記事を更新する</a> 33 <div class="dropdown-divider"></div> 34 <a class="dropdown-item text-danger" data-toggle="modal" data-target="#modal-delete-{{ $post->id }}"> 35 <i class="fas fa-trash-alt mr-1"></i>記事を削除する</a> 36 </div> 37 </div> 38 </div> 39 <!-- dropdown --> 40 41 <!-- modal --> 42 <div id="modal-delete-{{ $post->id }}" class="modal fade" tabindex="-1" role="dialog"> 43 <div class="modal-dialog" role="document"> 44 <div class="modal-content"> 45 <div class="modal-header"> 46 <button type="button" class="close" data-dismiss="modal" aria-label="閉じる"> 47 <span aria-hidden="true">×</span> 48 </button> 49 </div> 50 <form method="POST" action="{{ route('post.destroy', ['post' => $post]) }}"> 51 @csrf 52 @method('DELETE') 53 <div class="modal-body"> 54 削除します。よろしいですか? 55 </div> 56 <div class="modal-footer justify-content-between"> 57 <a class="btn btn-outline-grey" data-dismiss="modal">キャンセル</a> 58 <button type="submit" class="btn btn-danger">削除</button> 59 </div> 60 </form> 61 </div> 62 </div> 63 </div> 64 <!-- modal --> 65 @endif 66 </div> 67 <div class="card-body pt-0 pb-2"> 68 <div class="card-text"> 69 {!! nl2br(e($post->memo)) !!} 70 {{ $post->id }} 71 </div> 72 </div> 73 <div class="card-body pt-0 pb-2 pl-3"> 74 <div class="card-text"> 75 <post-like 76 :initial-is-liked-by='@json($post->isLikedBy(Auth::user()))' 77 :initial-count-likes='@json($post->count_likes)' 78 :authorized='@json(Auth::check())' 79 endpoint="{{ route('post.like', ['post' => $post]) }}"> 80 </post-like> 81 </div> 82 </div> 83 </div> 84 @endforeach 85</div> 86<div class="d-grid gap-2 col-6 mx-auto"> 87 <a href="{{ route('post.create') }}" class="btn btn-primary">投稿する</a> 88</div> 89<div class="d-grid gap-2 col-6 mx-auto"> 90 <a href="/home" class="btn btn-primary">マイページに戻る</a> 91</div> 92@endsection
補足情報(FW/ツールのバージョンなど)
OS:macOS
Docker
Laravel 6.20.34
PHP 7.3.24
vue 2.6.14
あなたの回答
tips
プレビュー