create, store~データの入力と登録
リソースルーティングでは、以下を意図している。
- edit
- データを編集する。フォームで編集する場合、フォームを持つビューを表示する。
- update
- 編集後の内容でデータベースのデータを更新する。editがフォームでの編集の場合、フォームのaction先をこのルートにする。
前提
モデルデータの操作で準備した枠組みを使う。ユーザー認証機能を持ち、ユーザーごとに入力されたシンプルな投稿記事Postを扱う。
流れ
- 編集する記事の
$idを指定してドメイン名/posts/(id)/editをGETリクエスト posts.editルートでPostsControllerのeditアクションを実行editアクションで編集フォームを含むビューを表示- 編集フォームの
actionからposts.updateへルーティング
→methodはPATCH posts.updateルートでPostControllerのupdateアクションを実行updateアクションでデータベース上のデータを更新
editアクションの呼び出し
リソースルーティングで以下のように設定されていて、ドメイン/posts/(id)/editからPostControllerのeditアクションにルーティングされる。ルーティング名はposts.edit。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ php artisan route:list +--------+-----------+------------------------+------------------+------------------------------------------------------------------------+--------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+-----------+------------------------+------------------+------------------------------------------------------------------------+--------------+ ........ | | POST | posts | posts.store | App\Http\Controllers\PostController@store | web,auth | | | GET|HEAD | posts | posts.index | App\Http\Controllers\PostController@index | web,auth | | | GET|HEAD | posts/create | posts.create | App\Http\Controllers\PostController@create | web,auth | | | GET|HEAD | posts/{post} | posts.show | App\Http\Controllers\PostController@show | web,auth | | | DELETE | posts/{post} | posts.destroy | App\Http\Controllers\PostController@destroy | web,auth | | | PUT|PATCH | posts/{post} | posts.update | App\Http\Controllers\PostController@update | web,auth | | | GET|HEAD | posts/{post}/edit | posts.edit | App\Http\Controllers\PostController@edit | web,auth | ........ |
編集対象の記事を指定してposts.editにGETリクエストでルーティングする例として、以下のようなアンカー要素がある。
|
1 |
<a href="{{ route('posts.edit', $post) }}">編集</a> |
route()メソッドの第2引数でモデルデータを指定すると、自動的にルーティングに沿った形でデータのidがURLに埋め込まれる。
上記の例ではルーティングがposts.editでURLがposts/{post}/editとなっているので、例えば記事idが3の記事の場合は以下のようなURLとなり、これがブラウザーにも表示される。
ドメイン名/posts/3/edit
コントローラー~editアクション
コントローラーでは、ビューの$titleと編集対象の記事のインスタンスを設定してresources/views/posts/edit.blade.phpを表示させる。
editアクションに来る際にURLに埋め込まれたidが、editアクションメソッドの引数$idとして受け取られる。この$idをPostモデルのfind()メソッドの引数に与えて、指定したidの記事データを取得する。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class PostController extends Controller { ........ public function edit($id) { $post = Post::find($id); return view('posts.edit', [ 'title' => '投稿編集', 'post' => $post, ]); } ........ } |
編集フォームビュー
bladeテンプレート
投稿を編集するフォームはposts/edit.blade.phpに以下の要領で記述。
ここでHTTPのメソッドはPOSTだが、ルーティングではPATCHメソッドを期待しているので、@method('patch')ディレクティブが必要。
|
1 2 3 4 5 6 7 8 |
<form method="post" action="{{ route('posts.update', $post) }}"> @csrf @method('patch') <div> <input type="text" name="comment" value="{{ $post->comment }}"> </div> <input type="submit" value="更新"> </form> |
actionで指定しているroute('posts.update', $post)はデータベースの更新アクションupdateへのルーティング。
PATCHに対するルーティングのURLはドメイン名/posts/(id)となる。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
$ php artisan route:list +--------+-----------+------------------------+------------------+------------------------------------------------------------------------+--------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+-----------+------------------------+------------------+------------------------------------------------------------------------+--------------+ ........ | | POST | posts | posts.store | App\Http\Controllers\PostController@store | web,auth | | | GET|HEAD | posts | posts.index | App\Http\Controllers\PostController@index | web,auth | | | GET|HEAD | posts/create | posts.create | App\Http\Controllers\PostController@create | web,auth | | | GET|HEAD | posts/{post} | posts.show | App\Http\Controllers\PostController@show | web,auth | | | DELETE | posts/{post} | posts.destroy | App\Http\Controllers\PostController@destroy | web,auth | | | PUT|PATCH | posts/{post} | posts.update | App\Http\Controllers\PostController@update | web,auth | | | GET|HEAD | posts/{post}/edit | posts.edit | App\Http\Controllers\PostController@edit | web,auth | ........ |
フォームリクエスト~バリデーション
編集フォームのバリデーションは入力フォームのところで作成したフォームリクエストを使う。
コントローラー~updateアクション
use指定
PostモデルとPostRequestに対するuse指定はフォーム入力で指定済み。
updateアクション
入力フォームのaction先で指定されたアクションメソッドで、編集後の内容でデータベースを更新する。
|
1 2 3 4 5 6 7 8 9 10 11 12 |
class PostController extends Controller { ........ public function update(PostRequest $request, $id) { // return 'update:' . $id; $post = Post::find($id); $post->update($request->only(['comment'])); return redirect()->route('posts.index'); } ........ } |
ここでの要点は以下の通り。
- フォームリクエストのバリデーションを有効にするため、
update()メソッドのインジェクションをPostRequestにしている update()メソッドの第2引数で、URLに埋め込まれたidが$idとして受け取られているPostクラスのfind()メソッドの引数に$idを渡して、指定したidの記事インスタンスを$postで参照している- 編集対象記事のインスタンス
$postのupdate()メソッドの引数に、更新対象の要素を渡している- 更新対象の要素は、引数のリクエストで得られたフォーム入力の
commentをonly()で限定している
- 更新対象の要素は、引数のリクエストで得られたフォーム入力の
- 更新後のデータを含めた一覧表示のため、
indexにリダイレクトしている
モデルでの$fillable設定
update()メソッドでのフォームリクエストによる登録はマスアサインメントになるので、モデルに$fillableの定義が必要(フォーム入力のところで定義済み)。
確認
ユーザーログイン状態で<a href="{{ route('posts.edit', $post) }}">編集</a>などでGETリクエストすると編集フォームのページが表示され、更新ボタンを押すとデータが更新される。
|
1 2 3 4 5 6 7 8 9 10 |
mysql> SELECT * FROM posts; +----+---------+-----------------------------------+---------------------+---------------------+ | id | user_id | comment | created_at | updated_at | +----+---------+-----------------------------------+---------------------+---------------------+ | 1 | 1 | user1の1つ目の投稿を編集 | 2021-10-09 10:34:47 | 2021-10-10 11:40:44 | | 2 | 1 | user1の2つ目の投稿 | 2021-10-09 10:35:01 | 2021-10-09 10:35:01 | | 3 | 2 | user2の1つ目の投稿を編集 | 2021-10-09 10:35:32 | 2021-10-10 10:56:10 | | 4 | 2 | user2の2つ目の投稿も編集 | 2021-10-09 10:35:45 | 2021-10-10 10:57:06 | +----+---------+-----------------------------------+---------------------+---------------------+ 4 rows in set (0.00 sec) |