2021/11/12 更新
投稿を update する
(新)を作成しました。こちらをご覧ください。
Contents
Postの詳細画面を作成する
一覧ページから投稿詳細画面に移動できるようにしましょう。
index.php
@foreach ($posts as $post) <div class="card-body"> <h5 class="card-title">タイトル:{{ $post->title }}</h5> <p class="card-text">内容:{{ $post->body }}</p> <a href="{{ route('posts.show', $post->id) }}" class="btn btn-primary">詳細へ</a> </div>
aタグのhrefにshowメソッドのルートをセットしてあげましょう。
解説
{{ route('posts.show', $post->id) }}
posts.showに関しては、「どの」postの詳細にいくのかを指定して上げる必要がありますよね。
なので、「$post→id」を渡してあげています。
PostController.phpのshowメソッド
public function show($id) { $post = Post::find($id); return view('posts.show', compact('post')); }
show($id)で$idを受け取ります。この$idはユーザーが詳細ボタンをクリックし投稿のIDが入っています。
なので、Postモデルから$idを使って検索をしています。
検索した$postをviewにコンパクト関数で渡します。
次にshow.blade.phpの中身を作成していきましょう。
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card-header"> <h5>タイトル:{{ $post->title }}</h5> </div> <div class="card-body"> <p class="card-text">内容:{{ $post->body }}</p> <p>投稿日時:{{ $post->created_at }}</p> </div> </div> </div> </div> @endsection
コントローラーから渡された$postの情報を表示することで詳細ページを表示しています。

Postを編集できるようにする
まずは詳細画面から、編集画面に移動できるようにしましょう。
show.blade.php
<div class="card-body"> <p class="card-text">内容:{{ $post->body }}</p> <p>投稿日時:{{ $post->created_at }}</p> <a href="{{ route('posts.edit', $post->id) }}" class="btn btn-primary">編集する</a> </div>
aタグでPostControllerのeditメソッドに送っています。
こちらも詳細画面に送る時と同様に、「どの」記事を編集するのかを「$post→id」で渡します。

PostController
public function edit($id) { $post = Post::find($id); return view('posts.edit', compact('post')); }
こちらはshowと同じです。
受け取った$idでPostモデルを通してpostsを検索。
検索したものを、$postとしてedit.bladeに渡しています。
edit.blade
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> @if ($errors->any()) <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form action="{{ route('posts.update', $post->id) }}" method="POST"> {{csrf_field()}} {{method_field('PATCH')}} <div class="form-group"> <label>タイトル</label> <input type="text" class="form-control" value="{{ $post->title }}" name="title"> </div> <div class="form-group"> <label>内容</label> <textarea class="form-control" rows="5" name="body">{{ $post->body }}</textarea> </div> <button type="submit" class="btn btn-primary">更新する</button> </form> </div> </div> </div> @endsection
formがまた出てきました。次はPATCHで更新処理をします。
ここで注目するべきは{{ method_field(‘PATCH’) }}です。
formタグ内のmethod=”PATCH”と書きたくなるのですが、、
HTMLフォームはPUT、PATCH、DELETEアクションをサポートしていません。。要は上記のように記載してもエラーが出てしまいます。
よって、擬似フォームメソッドというのを使います。下のリファレンスの「擬似フォームメソッド」を流し見するといいかなと思います。
edit.bladeでは初期値を持たせていますので、下記のように初期値を持ちつつ編集できるようになっているかなと思います。

(新)投稿を update する
次に編集内容をPostControllerのupdateメソッドを変更していきましょう。
public function update(PostRequest $request, $id) { $post = Post::find($id); $post->update($request->all()); return view('posts.show', compact('post')); }
update メソッドを使用して、更新処理をしましょう。
一行で更新処理が可能となり非常に便利ですね!
(旧)投稿を update する
次に編集内容をPostControllerのupdateメソッドを変更していきましょう。
public function update(PostRequest $request, $id) { $post = Post::find($id); $post -> title = $request -> title; $post -> body = $request -> body; $post -> save(); return view('posts.show', compact('post')); }
- PostRequestを通す。 初期値ではRequestになっていますので、PostRequestとしてバリデーションを行いましょう。
- $idで更新したいPostを探す。 こちらは、showでも同様のことを行っていました。
- $requestで受け取ったユーザーの入力値を$postに加えていく。 最後にsaveを忘れずにしましょう。
- user_idは???と思った方。鋭いですね。 ただ、postに関しては投稿したユーザーは変更がないはずなので変更しません。
ここまでできると、投稿の更新ができるようになったはずです!!
Postを削除できるようにする
CRUD機能の最後になりますが、Deleteをできるようにしてみましょう。
まずは削除ボタンを詳細画面におきましょう。
show.blade.php
<div class="card-body"> <p class="card-text">内容:{{ $post->body }}</p> <p>投稿日時:{{ $post->created_at }}</p> <a href="{{ route('posts.edit', $post->id) }}" class="btn btn-primary">編集する</a> <form action='{{ route('posts.destroy', $post->id) }}' method='post'> {{ csrf_field() }} {{ method_field('DELETE') }} <input type='submit' value='削除' class="btn btn-danger" onclick='return confirm("削除しますか??");'> </form> </div>
削除ボタンはformで書きます。
注目する点は{{ method_field(‘DELETE’) }}です。
HTMLフォームはPUT、PATCH、DELETEアクションをサポートしていません。よって擬似フォームメソッドを用いて送ります。
PostControllerのdestroyメソッドを編集していきます。
public function destroy($id) { $post = Post::find($id); $post -> delete(); return redirect()->route('posts.index'); }
ここでもfindを用いて、該当のPostを探しています。
そして探したものを削除、一覧ページに戻るように設定しました。
リレーションを使って投稿したユーザー名を表示する。

現在の一覧ページ。。。。
誰の記事かわからん!!!
ということで、ユーザー名を表示します。
リレーションを結ぶ。
現在のデータベースは以下の図。

Userは複数のPostを持ち、複数のCommentをもつ
Postは複数のCommentを持つ。
この関係性を各モデルに記載することで、データの取得が容易になります。
Userは複数のPostを持つ → User hasMany Posts / Post belongsTo User
Userは複数のCommentを持つ → User hasMany Comments / Comment belongsTo User
Postは複数のCommentを持つ → Post hasMany Comments / Comment belongsTo Post
例としては
特定の$postから投稿したユーザーの情報をリレーションを伝って取得できるようになります。
User.php に以下を追加しましょう。
class User extends Authenticatable { ------省略------- public function posts() { return $this->hasMany('App\Post'); } public function comments() { return $this->hasMany('App\Comment'); } }
次に
Post.php
class Post extends Model { protected $fillable = ['title', 'body']; public function comments() { return $this->hasMany('App\Comment'); } public function user() { return $this->belongsTo('App\User'); } }
最後にComment.php
class Comment extends Model { protected $fillable = ['body']; public function post() { return $this->belongsTo('App\Post'); } public function user() { return $this->belongsTo('App\User'); } }
以上でリレーションを結ぶことができました。
それでは実際にリレーションを使って一覧ページに投稿したユーザーの名前を表示してみましょう。
PostController
public function index() { $posts = Post::all(); $posts->load('user'); →追加 return view('posts.index', compact('posts')); }
今回「Eagerロード 」を追加しました。下記の「Eagerロード」を流し見しましょう。
簡潔にいうと、load(‘user’)で$postsに紐ずくuserにアクセスできるようにしています。
次をみてみましょう。
index.blade
<div class="card-body"> <h5 class="card-title">タイトル:{{ $post->title }}</h5> <p class="card-text">内容:{{ $post->body }}</p> <p class="card-text">投稿者:{{ $post->user->name }}</p> →追加 <a href="{{ route('posts.show', $post->id) }}" class="btn btn-primary">詳細へ</a> </div>
このように、$post→user→name
とすることで、投稿に紐ずくuserの名前を取得することができます。

そうしましたら、show.bladeにもuserの名前を表示できるようにしておきましょう。
Postの編集削除は本人でなければできないようにする。
CRUD機能をつけることができましたね。
しかし、1点問題があります。
それは、投稿したユーザー以外もPostを編集削除できてしまう点です。
投稿したユーザー以外が編集、削除をしようとした場合にはエラー画面に飛ばすように処理を書きましょう。
PostController
public function edit($id) { $post = Post::find($id); if(Auth::id() !== $post->user_id){ return abort(404); } return view('posts.edit', compact('post')); } ----省略------ public function update(PostRequest $request, $id) { $post = Post::find($id); if(Auth::id() !== $post->user_id){ return abort(404); } $post->update($request->all()); return view('posts.show', compact('post')); } ---省略----- public function destroy($id) { $post = Post::find($id); if(Auth::id() !== $post->user_id){ return abort(404); } $post -> delete(); return redirect()->route('posts.index'); }
ここでは、edit、update、destroyメソッドに
Auth::id() →ログイン中ユーザーのid
$post→user_id →該当の投稿のuser_id
を比較して、異なっていた場合は404エラーに飛ばす処理を書きました。
これでOKです!
ここで、webアプリの変な箇所を修正していきましょう。
ヘッダーのLaravelをクリックした時に、一覧ページに飛べるようにしましょう。
resources views layouts app.blade.php
<div id="app"> <nav class="navbar navbar-expand-md navbar-light bg-white shadow-sm"> <div class="container"> //<a class="navbar-brand" href="{{ url('/') }}"> <a class="navbar-brand" href="{{ route('posts.index') }}"> {{ config('app.name', 'Laravel') }} </a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="{{ __('Toggle navigation') }}"> <span class="navbar-toggler-icon"></span> </button>
これでOKです!
実際にヘッダーの「Laravel」をクリックして一覧画面に戻れるか確認をしてみましょう。
今回はここまで。また次回あいましょう!
コメントを残す