Laravel/Missing required parameterが改善できない・・
解決したいこと
今課題の練習で疑似Twitterを作成していて、
投稿した記事の編集画面を作成し画像の縦並び・・・を押すと遷移するようにしたいのですがエラーが起きてしまい何も進めなくなってしまい自分でネットで調べてもよくわからなくなってしまったため
ご指摘をいただきたいです。
発生している問題・エラー
Missing required parameter for [Route: tweets.update] [URI: tweets/{tweet}] [Missing parameter: tweet].
または、問題・エラーが起きている画像をここにドラッグアンドドロップ
Model
app/Models/Tweet.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\softDeletes;
class Tweet extends Model
{
use SoftDeletes;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'text'
];
public function user()
{
return $this->belongsTo(User::class);
}
public function favorites()
{
return $this->hasMany(Favorite::class);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function getUserTimeLine(Int $user_id)
{
return $this->where('user_id', $user_id)->orderBy('created_at', 'DESC')->paginate(50);
}
public function getTweetCount(Int $user_id)
{
return $this->where('user_id', $user_id)->count();
}
// 詳細画面
public function getTweet(Int $tweet_id)
{
return $this->with('user')->where('id', $tweet_id)->first();
}
// 一覧画面
public function getTimeLines(Int $user_id, Array $follow_ids)
{
$follow_ids[] = $user_id;
return $this->whereIn('user_id', $follow_ids)->orderBy('created_at', 'DESC')->paginate(50);
}
public function tweetStore(Int $user_id, Array $data)
{
$this->user_id = $user_id;
$this->text = $data['text'];
$this->save();
return;
}
public function getEditTweet(Int $user_id, Int $tweet_id)
{
return $this->where('user_id', $user_id)->where('id', $tweet_id)->first();
}
public function tweetUpdate(Int $tweet_id, Array $data)
{
$this->id = $tweet_id;
$this->text = $data['text'];
$this->update();
return;
}
public function tweetDestroy(Int $user_id, Int $tweet_id)
{
return $this->where('user_id', $user_id)->where('id', $tweet_id)->delete();
}
}
Controllers
app/Http/Controllers/TweetsController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Models\Tweet;
use App\Models\Comment;
use App\Models\Follower;
class TweetsController extends Controller
{
public function index(Tweet $tweet, Follower $follower)
{
$user = auth()->user();
$follow_ids = $follower->followingIds($user->id);
$following_ids = $follow_ids->pluck('followed_id')->toArray();
$timelines = $tweet->getTimelines($user->id, $following_ids);
return view('tweets.index', [
'user' => $user,
'timelines' => $timelines
]);
}
public function create()
{
$user = auth()->user();
return view('tweets.create', [
'user' => $user
]);
}
public function store(Request $request, Tweet $tweet)
{
$user = auth()->user();
$data = $request->all();
$validator = Validator::make($data, [
'text' => ['required', 'string', 'max:140']
]);
$validator->validate();
$tweet->tweetStore($user->id, $data);
return redirect('tweets');
}
public function show(Tweet $tweet, Comment $comment)
{
$user = auth()->user();
$tweet = $tweet->getTweet($tweet->id);
$comments = $comment->getComments($tweet->id);
return view('tweets.show', [
'user' => $user,
'tweet' => $tweet,
'comments' => $comments
]);
}
public function edit(Tweet $tweet)
{
$user = auth()->user();
$tweets = $tweet->getEditTweet($user->id, $tweet->id);
if (!isset($tweets)) {
return redirect('tweets');
}
return view('tweets.edit', [
'user' => $user,
'tweets' => $tweets
]);
}
public function update(Request $request, Tweet $tweet)
{
$data = $request->all();
$validator = Validator::make($data, [
'text' => ['required', 'string', 'max:140']
]);
$validator->validate();
$tweet->tweetUpdate($tweet->id, $data);
return redirect('tweets');
}
public function destroy(Tweet $tweet)
{
$user = auth()->user();
$tweet->tweetDestroy($user->id, $tweet->id);
return back();
}
}
View
resources/views/tweets/show.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center mb-5">
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$tweet->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $tweet->user->name }}</p>
<a href="{{ url('users/' .$tweet->user->id) }}" class="text-secondary">{{ $tweet->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $tweet->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{!! nl2br(e($tweet->text)) !!}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($tweet->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$tweet->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$tweet->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$tweet->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($tweet->comments) }}</p>
</div>
<div class="d-flex align-items-center">
@if (!in_array($user->id, array_column($tweet->favorites->toArray(), 'user_id'), TRUE))
<form method="POST" action="{{ url('favorites/') }}" class="mb-0">
@csrf
<input type="hidden" name="tweet_id" value="{{ $tweet->id }}">
<button type="submit" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
</form>
@else
<form method="POST" action="{{ url('favorites/' .array_column($tweet->favorites->toArray(), 'id', 'user_id')[$user->id]) }}" class="mb-0">
@csrf
@method('DELETE')
<button type="submit" class="btn p-0 border-0 text-danger"><i class="fas fa-heart fa-fw"></i></button>
</form>
@endif
<p class="mb-0 text-secondary">{{ count($tweet->favorites) }}</p>
</div>
</div>
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-8 mb-3">
<ul class="list-group">
@forelse ($comments as $comment)
<li class="list-group-item">
<div class="py-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$comment->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $comment->user->name }}</p>
<a href="{{ url('users/' .$comment->user->id) }}" class="text-secondary">{{ $comment->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $comment->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="py-3">
{!! nl2br(e($comment->text)) !!}
</div>
</li>
@empty
<li class="list-group-item">
<p class="mb-0 text-secondary">コメントはまだありません。</p>
</li>
@endforelse
<li class="list-group-item">
<div class="py-3">
<form method="POST" action="{{ route('comments.store') }}">
@csrf
<div class="form-group row mb-0">
<div class="col-md-12 p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $user->name }}</p>
<a href="{{ url('users/' .$user->id) }}" class="text-secondary">{{ $user->screen_name }}</a>
</div>
</div>
<div class="col-md-12">
<input type="hidden" name="tweet_id" value="{{ $tweet->id }}">
<textarea class="form-control @error('text') is-invalid @enderror" name="text" required autocomplete="text" rows="4">{{ old('text') }}</textarea>
@error('text')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-12 text-right">
<p class="mb-4 text-danger">140文字以内</p>
<button type="submit" class="btn btn-primary">
ツイートする
</button>
</div>
</div>
</form>
</div>
</li>
</ul>
</div>
</div>
</div>
@endsection
resources\views\tweets\index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8 mb-3 text-right">
<a href="{{ url('users') }}">ユーザ一覧 <i class="fas fa-users" class="fa-fw"></i> </a>
</div>
@if (isset($timelines))
@foreach ($timelines as $timeline)
<div class="col-md-8 mb-3">
<div class="card">
<div class="card-haeder p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$timeline->user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $timeline->user->name }}</p>
<a href="{{ url('users/' .$timeline->user->id) }}" class="text-secondary">{{ $timeline->user->screen_name }}</a>
</div>
<div class="d-flex justify-content-end flex-grow-1">
<p class="mb-0 text-secondary">{{ $timeline->created_at->format('Y-m-d H:i') }}</p>
</div>
</div>
<div class="card-body">
{!! nl2br(e($timeline->text)) !!}
</div>
<div class="card-footer py-1 d-flex justify-content-end bg-white">
@if ($timeline->user->id === Auth::user()->id)
<div class="dropdown mr-3 d-flex align-items-center">
<a href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fas fa-ellipsis-v fa-fw"></i>
</a>
<div class="dropdown-menu" aria-labelledby="dropdownMenuLink">
<form method="POST" action="{{ url('tweets/' .$timeline->id) }}" class="mb-0">
@csrf
@method('DELETE')
<a href="{{ url('tweets/' .$timeline->id .'/edit') }}" class="dropdown-item">編集</a>
<button type="submit" class="dropdown-item del-btn">削除</button>
</form>
</div>
</div>
@endif
<div class="mr-3 d-flex align-items-center">
<a href="{{ url('tweets/' .$timeline->id) }}"><i class="far fa-comment fa-fw"></i></a>
<p class="mb-0 text-secondary">{{ count($timeline->comments) }}</p>
</div>
<div class="d-flex align-items-center">
@if (!in_array($user->id, array_column($timeline->favorites->toArray(), 'user_id'), TRUE))
<form method="POST" action="{{ url('favorites/') }}" class="mb-0">
@csrf
<input type="hidden" name="tweet_id" value="{{ $timeline->id }}">
<button type="submit" class="btn p-0 border-0 text-primary"><i class="far fa-heart fa-fw"></i></button>
</form>
@else
<form method="POST" action="{{ url('favorites/' .array_column($timeline->favorites->toArray(), 'id', 'user_id')[$user->id]) }}" class="mb-0">
@csrf
@method('DELETE')
<button type="submit" class="btn p-0 border-0 text-danger"><i class="fas fa-heart fa-fw"></i></button>
</form>
@endif
<p class="mb-0 text-secondary">{{ count($timeline->favorites) }}</p>
</div>
</div>
</div>
</div>
@endforeach
@endif
</div>
<div class="my-4 d-flex justify-content-center">
{{ $timelines->links() }}
</div>
</div>
@endsection
自分ではルーティング定義している箇所とBladeで利用している箇所が相違があるのかなと思いやってみたのですが見当違いなのか改善がされなかったです。
まだまだ勉強不足で申し訳ありませんが、ご指摘をいただきたいです。
よろしくお願いします。
「追記」
編集ページのView
resources/views/tweets/edit.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Update</div>
<div class="card-body">
<form method="POST" action="{{ route('tweets.update', ['tweets' => $tweets]) }}">
@csrf
@method('PUT')
<div class="form-group row mb-0">
<div class="col-md-12 p-3 w-100 d-flex">
<img src="{{ asset('storage/profile_image/' .$user->profile_image) }}" class="rounded-circle" width="50" height="50">
<div class="ml-2 d-flex flex-column">
<p class="mb-0">{{ $user->name }}</p>
<a href="{{ url('users/' .$user->id) }}" class="text-secondary">{{ $user->screen_name }}</a>
</div>
</div>
<div class="col-md-12">
<textarea class="form-control @error('text') is-invalid @enderror" name="text" required autocomplete="text" rows="4">{{ old('text') ? : $tweets->text }}</textarea>
@error('text')
<span class="invalid-feedback" role="alert">
<strong>{{ $message }}</strong>
</span>
@enderror
</div>
</div>
<div class="form-group row mb-0">
<div class="col-md-12 text-right">
<p class="mb-4 text-danger">140文字以内</p>
<button type="submit" class="btn btn-primary">
ツイートする
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
route設定ファイル
routes\web.php
<?php
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
Route::group(['middleware' => 'auth'], function() {
// ユーザ関連
Route::resource('users', 'App\Http\Controllers\UsersController', ['only' => ['index', 'show', 'edit', 'update']]);
// フォロー/フォロー解除を追加
Route::post('users/{id}/follow', 'App\Http\Controllers\UsersController@follow')->name('follow');
Route::delete('users/{id}/unfollow', 'App\Http\Controllers\UsersController@unfollow')->name('unfollow');
// ツイート関連
Route::resource('tweets', 'App\Http\Controllers\TweetsController', ['only' => ['index', 'create', 'store', 'show', 'edit', 'update', 'destroy']]);
// コメント関連
Route::resource('comments', 'App\Http\Controllers\CommentsController', ['only' => ['store']]);
// いいね関連
Route::resource('favorites', 'App\Http\Controllers\FavoritesController', ['only' => ['store', 'destroy']]);
});
route設定 php artisan route:list
GET|HEAD / ..................................................................................................
POST _ignition/execute-solution ignition.executeSolution › Spatie\LaravelIgnition › ExecuteSolutionContr…
GET|HEAD _ignition/health-check ....... ignition.healthCheck › Spatie\LaravelIgnition › HealthCheckController
POST _ignition/update-config .... ignition.updateConfig › Spatie\LaravelIgnition › UpdateConfigController
GET|HEAD api/user ...........................................................................................
GET|HEAD arrilot/load-widget .................................. Arrilot\Widgets › WidgetController@showWidget
POST comments ................................................. comments.store › CommentsController@store
POST favorites .............................................. favorites.store › FavoritesController@store
DELETE favorites/{favorite} ............................... favorites.destroy › FavoritesController@destroy
GET|HEAD home ................................................................... home › HomeController@index
GET|HEAD login ................................................... login › Auth\LoginController@showLoginForm
POST login ................................................................... Auth\LoginController@login
POST logout ........................................................ logout › Auth\LoginController@logout
GET|HEAD password/confirm ................. password.confirm › Auth\ConfirmPasswordController@showConfirmForm
POST password/confirm ............................................ Auth\ConfirmPasswordController@confirm
POST password/email ................... password.email › Auth\ForgotPasswordController@sendResetLinkEmail
GET|HEAD password/reset ................ password.request › Auth\ForgotPasswordController@showLinkRequestForm
POST password/reset ................................ password.update › Auth\ResetPasswordController@reset
GET|HEAD password/reset/{token} ................. password.reset › Auth\ResetPasswordController@showResetForm
GET|HEAD register ................................... register › Auth\RegisterController@showRegistrationForm
POST register .......................................................... Auth\RegisterController@register
GET|HEAD sanctum/csrf-cookie .............. sanctum.csrf-cookie › Laravel\Sanctum › CsrfCookieController@show
GET|HEAD tweets ....................................................... tweets.index › TweetsController@index
POST tweets ....................................................... tweets.store › TweetsController@store
GET|HEAD tweets/create .............................................. tweets.create › TweetsController@create
GET|HEAD tweets/{tweet} ................................................. tweets.show › TweetsController@show
PUT|PATCH tweets/{tweet} ............................................. tweets.update › TweetsController@update
DELETE tweets/{tweet} ........................................... tweets.destroy › TweetsController@destroy
GET|HEAD tweets/{tweet}/edit ............................................ tweets.edit › TweetsController@edit
GET|HEAD users .......................................................... users.index › UsersController@index
POST users/{id}/follow .................................................. follow › UsersController@follow
DELETE users/{id}/unfollow ............................................ unfollow › UsersController@unfollow
GET|HEAD users/{user} ..................................................... users.show › UsersController@show
PUT|PATCH users/{user} ................................................. users.update › UsersController@update
GET|HEAD users/{user}/edit ................................................ users.edit › UsersController@edit
Showing [35] routes
0