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
。
|
$ 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リクエストでルーティングする例として、以下のようなアンカー要素がある。
|
<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の記事データを取得する。
|
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')
ディレクティブが必要。
|
<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)
となる。
|
$ 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先で指定されたアクションメソッドで、編集後の内容でデータベースを更新する。
|
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リクエストすると編集フォームのページが表示され、更新ボタンを押すとデータが更新される。
|
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) |