どうしたらいいでしょうか?
こんな疑問に答えていきます。
なお、今回は主に「LaravelでjQueryを使ってPOST(DELETE)の通信を行う」ことをテーマに解説していきます。
【前提】
・Laravel8系
・jQuery 3.6
※なお、まだjQueryを導入できていない方はLaravelでjavascript、jQueryを使う方法を参考に、導入してください。
Laravelでjavascript、jQueryを使う方法
あなたlaravelでjavascriptやjqueryを使うにはどうしたらいいのだろうか 今回は上記のような疑問を抱えている方に向けて、Laravelでjavascrip ...
続きを見る
Laravel8でjQueryを使ってAjax通信を行う方法
今回行いたい挙動は、以下だとします。
・削除ボタンを押したらajax通信で非同期で削除を行う
・削除処理の成功失敗に応じて、フラッシュメッセージを表示する
ファイルの構成は以下のとおりです。
App
//コントローラー
- Http
-- Controllers
--- Api
---- Admin
----- DeleteUserController.php
//js
- resources
-- js
--- deleteconfirm.js
//サービス
- Http
-- Services
--- UserService.php
//ルーティング
- routes
-- user.php
//ビュー
- resources
-- views
--- admin
---- users
----- index.blade.php
では、jsと、phpの各ファイルの中身を解説していきます。
js(jQuery)側
js(jquery側)のコードは以下のような感じになります。
ちなみに、「delete_button_10」というようなid属性を持ったボタンをクリックした時に処理が走るようにします。
(後ほど、view側のコードも紹介します。)
resources/js/deleteconfirm.js$( function () { $( "[id^=delete_button]" ).on( "click", function () { const id = $( this ).attr( "id" ).substr( 14 );//delete_button_IDのIDだけ切り出す console.log( id ); //csrf対策 $.ajaxSetup( { headers: { 'X-CSRF-TOKEN': $( 'meta[name="csrf-token"]' ).attr( 'content' ) } } ); if ( confirm( '本当に削除してもいいですか?' ) ) { $.ajax( { type: "post", //形式 url: `/admin/users/api/delete/${ id }`, //リクエストURL dataType: 'json', data: { "id": id, "_method": "DELETE" } //deleteメソッドを追加 } ) //成功時の処理 .done( ( res ) => { if ( res[ "status" ] == "success" ) { //view側の削除したいHTML要素のidは「row_数字(ID)」とする $( `#row_${ id }` ).remove(); flashMessage( id, res[ "status" ], res[ "message" ] ); } } ) //失敗時の処理 .fail( function ( jqXHR, textStatus, errorThrown ) { console.log( jqXHR ); console.log( textStatus ); console.log( errorThrown ); flashMessage( id, 'error', '削除に失敗しました。' ); } ); } } ); /** * 処理終了時にフラッシュメッセージを表示 * @param {int} id * @param {str} status * @param {str} message */ function flashMessage ( id, status, message ) { let bgColor = 'bg-red-300'; let dom = `<div id ="flash_${ id }" class="${ bgColor } w-1/2 mx-auto mb-4 p-2 text-white"> ${ message } </div>`; if ( status == "error" ) { $( ".container" ).append( dom ); } else { bgColor = 'bg-blue-300'; dom = `<div id ="flash_${ id }" class="${ bgColor } w-1/2 mx-auto mb-4 p-2 text-white"> ${ message } </div>`; $( ".container" ).append( dom ); } //2秒後に消す setTimeout( function () { $( `#flash_${ id }` ).remove(); }, 2000 ); } } )
view側のコードは次のようになっています。
....省略...
<meta name="csrf-token" content="{{ csrf_token() }}">
....省略...
<div class="container">
....省略...
<tbody>
@foreach ($users as $user)
<tr id="row_{{ $user->id }}">
<td class="px-4 py-3"> {{ $user->name }}</td>
<td class="px-4 py-3"> {{ $user->email }}</td>
<td class="px-4 py-3">{{ $user->created_at }}</td>
<td class="px-4 py-3">
<button onclick="location.href='{{ route('admin.users.edit', ['user' => $user->id]) }}'"
class="text-white bg-indigo-400 border-0 py-2 px-4 focus:outline-none hover:bg-indigo-500 rounded">編集</button>
</td>
<td class="px-4 py-3">
<button id="delete_button_{{ $user->id }}"
class="text-white bg-red-400 border-0 py-2 px-4 focus:outline-none hover:bg-red-500 rounded">削除</button>
</td>
</tr>
@endforeach
</tbody>
....省略...
ちなみに、view側には以下のコードは必ず埋め込んでおいてください。
<meta name="csrf-token" content="{{ csrf_token() }}">
csrf対策のものです。
こちらがないと通信時に419エラーになります。
ajax通信の雛形
さきほど紹介したjsファイルの中の以下の部分がajax通信の雛形です。
$.ajax( {
type: "post", //形式
url: `/admin/users/api/delete/${ id }`, //リクエストURL
dataType: 'json', //データタイプ
data: { "id": id, "_method": "DELETE" } //deleteメソッドを追加
} )
削除処理の場合はdataキーに「"_method": "DELETE"」を指定してあげるとうまくいきます。
これがないと「405 (Method Not Allowed)」で怒られます。
PHP(laravel)側①ルーティングファイル
php側のコードを紹介していきます。
今回は、「ドメイン/admin/users/api/delete/削除対象のユーザID」にリクエストをしたら削除をしたいので、まずはそちらを明示するルーティングファイルを編集します。
コードは以下のとおりです。
routes/admin.php//API Route::delete('/users/api/delete/{id}', [DeleteUserController::class, 'delete']) ->middleware('auth:admins') ->name('users.delete');
こちらの記述をすることで、リクエストが来た場合に「DeleteUserController」の「deleteメソッド」が走ることになります。
ルーティングファイルの注意点
削除処理の場合ルーティングファイルで「Route::delete」としてあげてくださいね。
ここをpostとかにすると「405 (Method Not Allowed)」で怒られます。
削除 → Route::delete
更新 → Route::put
です。
PHP(laravel)側②コントローラー
次にコントローラー側の記述です。
今回は次のように記述しました。
app/Http/Controllers/Api/Admin/DeleteUserrController.php<?php namespace App\Http\Controllers\Api\Admin; use App\Http\Controllers\Controller; use App\Http\Services\UserService; class DeleteUserController extends Controller { /** * @var UserService */ protected $userService; public function __construct(UserService $userService) { $this->middleware('auth:admins'); $this->userService = $userService; } public function delete($id) { //ユーザーの削除を行う try { $this->userService->delete($id); $status = 'success'; $message = '削除が完了しました。'; $returnArr = [ 'status' => $status, 'message' => $message ]; return response()->json($returnArr); } catch (\Throwable $th) { $status = 'error'; $message = '削除に失敗しました。'; $returnArr = [ 'status' => $status, 'message' => $message ]; return response()->json($returnArr); } } }
ajax通信で受け取った対象idを、userServiceクラスに渡してあげて、処理を走らせる内容になっています。
注意点は、レスポンスを返す時の形です。
json形式で返してあげないとエラーになります。
「 return response()->json($returnArr);」という記述の部分でjsonで返しています。
PHP(laravel)側③サービスクラス
最後にサービスクラスです。
コードは次の通り。
app/Http/Services/UserService.php<?php namespace App\Http\Services; use Illuminate\Support\Facades\Hash; use App\Models\User; use Illuminate\Support\Carbon; class UserService { public function __construct() { } /** * ユーザー削除 */ public function delete($id) { $user = User::findOrFail($id); $user->deleted_at = Carbon::now()->format("Y-m-d H:i:s"); $user->save(); } }
今回の自分の実装では、削除は物理削除ではなく、deleted_atに日付を入れるだけとしています。
別に物理削除でも構いません。
delete()のメソッドはお好きにカスタマイズしてみてください。
PHP側のコードの紹介、解説は以上になります。
Laravel×Ajaxで405エラー、419エラーが出る時の対処法
コードの解説時にもいくつか紹介しましたが、LaravelでjQueryを使ったAjax通信を実装する時によく出てくる405エラーと419エラーの解決方法を、それぞれ紹介します。
405 (Method Not Allowed)
メソッド(post、get、delet、put)が許可されていない場合に起きるエラーです。
このエラーが出た場合は以下を確認してください。
・jQuery側 → ajaxのdataキーで「 "_method": "実行したいメソッド"」を記述していること
・php側 → ルーティングファイルで実行したいメソッドを指定していること(Route::post、Route::deleteなど)
419 (unknown status)
こちらはcsrfの対策ができていない場合に起きるエラーです。
次のことを確認してください。
・jQuery側 → ajax通信の前にheaderにcsrfトークンを設定していること(設定するためのコードはこの記事のコード紹介のところに載せてあります)
・blade.php側 → meta name属性でcsrfの記述。「<meta name="csrf-token" content="{{ csrf_token() }}">」を設定してください。
補足:csrfとは
補足的に説明です。
csrfとはクロスサイトリクエストフォージェリの略称です。
クロスサイトリクエストフォージェリは、認証済みユーザーに代わって不正なコマンドを実行する、悪意のある攻撃の一種です。
公式ドキュメントでは上記のように解説されています。
要は「悪意をもった第三者が不正にあなたの情報を利用するための攻撃」だと認識しておけばOKです。
攻撃の細かい仕組みを知りたい方はIPAの公式記事が参考になると思います。
ということで今回は、LaravelでjQueryを使ってAjax通信を行う場合の解説でした。