どうしたらいいでしょうか?
こんな疑問に答えていきます。
なお、今回は主に「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側のコードも紹介します。)
$( 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」にリクエストをしたら削除をしたいので、まずはそちらを明示するルーティングファイルを編集します。
コードは以下のとおりです。
//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)側②コントローラー
次にコントローラー側の記述です。
今回は次のように記述しました。
<?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)側③サービスクラス
最後にサービスクラスです。
コードは次の通り。
<?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通信を行う場合の解説でした。