前のページ

「リソースコントローラー版つぶやきアプリ⑤」つぶやきの編集と削除(Laravel12)

今回はリソースコントローラー版のつぶやきの編集と削除をします。

つぶやきアプリ作成の最後の解説になります。


つぶやき一覧に編集ボタンを設置

つぶやき一覧のページにつぶやきを編集する為のボタンを設置します。

index.blade.phpの編集をします。

<div class="wrap">
    <h2>つぶやき一覧</h2>
    @foreach ($tweets as $tweet)
        <div class="tweet">
            <p>{{$tweet->body}}</p>
            <a href=""><button>編集</button></a>
        </div>
    @endforeach
</div>

<style>
    .wrap{
        width: 80%;
        margin-left:auto;
        margin-right:auto;
        padding-top: 50px;
    }
    .tweet{
        margin-bottom: 40px;
    }
    p{
        background-color:#f2eeed;
        padding: 5px;
    }
</style>

「http://localhost:8888/tweet/index」にアクセスして下記の表示になるかを確認して下さい。


20241124_170401_tweet24.jpg

まだ編集ボタンは機能していませんがこれから機能させます。


つぶやきの編集の流れ

あなたがつぶやきを編集する時をイメージすると考えやすいと思います。

下記の手順を踏むはずです。

  1. まず編集のページに移動

  2. つぶやきの内容を変更して更新する

だからまず編集のページに移動する為のアクションを設定します。


つぶやきの編集ページに移動する為の設定

TweetController.phpに下記の記述をします。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Tweet;

class TweetController extends Controller
{
    public function create()
    {
        return view('tweet.create');
    }

    public function store(Request $request)
    {
        $tweets = new Tweet();
        $tweets->body = $request->body;
        $tweets->save();
        return back()->with('message');
    }

    public function index()
    {
        $tweets = Tweet::all();
        return view('tweet.index', compact('tweets'));
    }

    //ここから追加
    public function edit(Tweet $tweet){
        return view('tweet.edit', compact('tweet'));
    }
    //ここまで追加


}

editアクションの引数(Tweet $tweet)についてはあとで説明するのでひとまずそのまま記述してください。

次はビューです。


ビュー

編集ページは作成ページとほぼ同じなのでひとまずcreate.blade.phpをコピーして「tweet > resources > views > tweet」の下にedit.blade.phpを作成して貼り付けます。

一応ファイルの中身を掲載します。

<div class="wrap">
    <h1>つぶやきの編集</h1>
    <form method="post" action="{{ route('tweet.store') }}">
        @csrf
        <div>
            <textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く"></textarea>
        </div>
        <button type="submit">つぶやく</button>
    </form>
</div>

<style>
    .wrap{
        width: 1000px;
        margin-left:auto;
        margin-right:auto;
        margin-top: 100px;
    }
    .flash{
        border:1px solid red;
        text-align: center;
        padding: 5px;
    }
    button{
        margin-top: 50px;
    }
</style>

ページにアクセスして表示されるかを確認したいのでURLをチェックする為に「php artisan route:list」をすると下記の表示になります。

 GET|HEAD  tweet/create ................ tweet.create › TweetController@create
 GET|HEAD  tweet/{tweet}/edit .......... tweet.edit   › TweetController@edit
 GET|HEAD  tweet/index ................. tweet.index  › TweetController@index
 POST      tweet/store ................. tweet.store  › TweetController@store

今回該当するeditアクションのURLを見ると今までとは違うことが分かります。

edtiアクションの「{tweet}」が今まではありませんでした。

これはパラメーターと言います。

パラメーターは1・2・3・4などの数値のことです。

もっと言うとtweetsテーブルのレコードのidカラムの値が該当します。

20241124_175455_tweet25.jpg

上記の例だとtweetに1が入った「tweet/1/edit」にアクセスしてつぶやきを作成するページと同じ表示になったら大丈夫です。

ちなみになぜパラメーターが必要かですがつぶやきを編集するのにパラメーターがないとどのつぶやきを編集するかが分からないからです。

だから編集・更新・削除する場合は必ずパラメーターが必要になります。

下記の表示になるのを確認して下さい。


20241124_181210_tweet26.jpg


つぶやきを編集する時はフォームの中に編集したい内容が表示されてないと変ですよね。

だからコードを下記に修正します。

<div class="wrap">
    <h1>つぶやきの編集</h1>
    <form method="post" action="{{ route('tweet.store') }}">
        @csrf
        <div>
            <textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く">{{ $tweet->body }}</textarea>   //この行を修正
        </div>
        <button type="submit">つぶやく</button>
    </form>
</div>

<style>
    .wrap{
        width: 1000px;
        margin-left:auto;
        margin-right:auto;
        margin-top: 100px;
    }
    .flash{
        border:1px solid red;
        text-align: center;
        padding: 5px;
    }
    button{
        margin-top: 50px;
    }
</style>

「$tweet->body」の「body」はカラム名ですが「$tweet」何なのか分からないと思います。

これはコントローラーのeditアクションの「Tweet $tweet」に該当します。

public function edit(Tweet $tweet){
    return view('tweet.edit', compact('tweet'));
}

editアクションの引数を「Tweet $tweet」にしていますがTweetはモデル名でtweetsテーブルのデータを$tweetという変数として使うことができるという認識で大丈夫です。

そしてcompactで$tweetをビューに渡してビューで「{{ $tweet->body }}」と記述することでつぶやきの内容を表示しています。

「body」はtweetsテーブルのカラム名です、「$tweet->カラム名」と記述すればカラムの値を表示できます。

これで「tweet/1/edit」を再読み込みするとつぶやきの内容がフォームに入っているのを確認できます。


20241124_191804_tweet27.jpg

それではつぶやきの更新をします。


つぶやきの更新

アクションは下記のどれになるか分かりますか?

tweet ................. tweet.index   › TweetController@index
tweet ................. tweet.store   › TweetController@store
tweet/create .......... tweet.create  › TweetController@create
tweet/{tweet} ......... tweet.show    › TweetController@show
tweet/{tweet} ......... tweet.update  › TweetController@update
tweet/{tweet} ......... tweet.destroy › TweetController@destroy
tweet/{tweet}/edit .... tweet.edit    › TweetController@edit

updateになります。

TweetController.phpのupdateアクションの記述を下記に変更します。

public function update(Request $request, Tweet $tweet){
    $tweet->body = $request->body;
    $tweet->save();
    return back();
}

updateアクションの引数に「Tweet $tweet」を追加しています。

edit.blade.phpに「{{ $tweet->body }}」があったのを覚えていますか?

<textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く">{{ $tweet->body }}</textarea>

これの値を変更する為にupdateアクションの引数に「Tweet $tweet」を追加しました。

下記のコードはつぶやきの作成の時と全く同じです。

$tweet->body = $request->body;
$tweet->save();
return back();

「$tweet->body」はtweetsテーブルのbodyカラムの内容で「$request->body」は編集フォームの内容です。

「$tweet->save();」は変更したつぶやきの内容を保存して「return back();」は更新後に同じページにリダイレクトします。

これでコントローラーの修正はできましたがビュー(edit.blade.php)の修正はしていないので修正します。


ビューの修正

edit.blade.phpのコードを下記にします。

<div class="wrap">
    <h1>つぶやきの編集</h1>
    <form method="post" action="{{ route('tweet.update', $tweet) }}">     //この行を修正
        @csrf
        @method('put')    //この行を追加
        <div>
            <textarea name="body" cols="40" rows="10" placeholder="ここにつぶやきの内容を書く">{{ $tweet->body }}</textarea>
        </div>
        <button type="submit">つぶやく</button>
    </form></div>

<style>
    .wrap{
        width: 80%;
        margin-left:auto;
        margin-right:auto;
        padding-top: 50px;
    }
    button{
        margin-top: 20px;
    }
</style>

「<form method="post" action="{{ route('tweet.update', $tweet) }}"」に「$tweet」が追加されていますがこれはパラメーターになります。

先ほど確認した「{tweet}」です。

tweet/{tweet}/edit .... tweet.edit › TweetController@edit

それと更新するときは「@csrf」の下の行に「@method('put')」を書かないとエラーになる仕様になっています。

これでビューも完成です。

ところでupdateアクションに対してビューを作成してないですがなぜか分かりますか?

更新は処理だけで表示するビューがなくても成立するからupdateの時はビュー作を成しません。

同様に作成するstoreアクション・削除するdestroyアクションもビューを作成しないくていいです。


編集ボタンの機能

index.blade.phpの編集ボタンがまだ機能していないので機能させます。

下記のコードに修正します。

<div class="wrap">
    <h2>つぶやき一覧</h2>
    @foreach ($tweets as $tweet)
        <div class="tweet">
            <p>{{$tweet->body}}</p>
            <a href="{{ route('tweet.edit', $tweet) }}"><button>編集</button></a>    //この行を修正
        </div>
    @endforeach
</div>

<style>
    .wrap{
        width: 80%;
        margin-left:auto;
        margin-right:auto;
        padding-top: 50px;
    }
    .tweet{
        margin-bottom: 40px;
    }
    p{
        background-color:#f2eeed;
        padding: 5px;
    }
</style>

これでつぶやき一覧のページ(http://localhost:8888/tweet)で編集ボタンをクリックするとつぶやきの編集ができます。

最後につぶやきを削除できるようにします。


つぶやきの削除

つぶやき一覧のページで削除ボタンを設置します。

index.blade.phpのコードを下記に変更します。

<div class="wrap">
    <h2>つぶやき一覧</h2>
    @foreach ($tweets as $tweet)
        <div class="tweet">
            <p>{{$tweet->body}}</p>
            <div class="flex">
                <a href="{{ route('tweet.edit', $tweet) }}"><button>編集</button></a>
                <form method="post" action="{{route('tweet.destroy', $tweet)}}">
                    @csrf
                    @method('delete')
                    <button type="submit">削除</button>
                </form>
            </div>
        </div>
    @endforeach
</div>

<style>
    .wrap{
        width: 80%;
        margin-left:auto;
        margin-right:auto;
        padding-top: 50px;
    }
    .tweet{
        margin-bottom: 40px;
    }
    .flex{
        margin-top: 20px;
        display: flex;
        column-gap:10px;
    }
    p{
        background-color:#f2eeed;
        padding: 5px;
    }
</style>

ここまでの解説が理解できた人は理解が楽だと思いますが2点違いがあります。

1点目は「@method('delete')」です。

削除する時はこれを付けないとエラーが出る仕様になっています。

2点目は削除の時はformタグを使う点です。

削除の時はformタグを使うと覚えていいです。

コントローラーの記述をしていないのでTweetController.phpのコードを下記にします。

public function destroy(Tweet $tweet){
    $tweet->delete();
    return back();
}

引数の「Tweet $tweet」はupdateアクションの時と考え方が全く同じで「$tweet」は削除しようとしているtweetsテーブルの該当のレコードになります。

それを「->delete()」で削除します。

これでリソースコントローラー版のつぶやきアプリの作成は完成です。

通常のアプリではログインを先にしないとつぶやきを投稿したり編集したり削除できないですがあえてログイン機能を入れていません。

またルーティングの設定とコントローラーの記述が楽なリソースコントローラーをあえて使っていますが次のアプリの作成からログイン機能の解説とリソースコントローラーではないコントローラーを使います。

戻る