概要
Laravelアプリで、
▪️ 一覧ページ(indexやoneday)
▪️ 詳細ページ(show)
▪️ 編集ページ(edit)
を行き来する際に、「元の一覧ページ」に確実に戻れるボタンの実装方法です。
さらに、外部URLをブロックしてセキュリティを確保します。
なぜ必要か
▪️ URL::previous() やブラウザの戻るボタンは、リロードや別タブ操作で崩れやすい
▪️ 一覧の種類(index or oneday)を保持したい
index、oneday両方とも同じshowへ移動できる場合の戻る処理
▪️ 悪意ある外部サイトに飛ばされるオープンリダイレクトを防止したい
実装の流れ
1. 一覧 or onedayから詳細へ back_url を付けて遷移
同じaタグ
// /resources/views/tasks/one_day.blade.php
<a href="{{ route('tasks.show', ['task' => $task->id, 'back_url' => url()->full()]) }}"
class="block transition-all duration-200 rounded hover:shadow-lg hover:-translate-y-0.5">
// /resources/views/tasks/index.blade.php
<a href="{{ route('tasks.show', ['task' => $task->id, 'back_url' => url()->full()]) }}"
class="block transition-all duration-200 rounded hover:shadow-lg hover:-translate-y-0.5">
2. 詳細(show)で back_url を受け取り、外部URLをブロック
/app/Http/Controllers/TaskController.php
public function show(Request $request, $id)
{
// ----- ユーザー情報取得
/** @var \App\Models\User $user */
$user = Auth::user();
// ----- タスク情報取得
$task = $user->tasks()
->with('taskCategory')
->findOrFail($id);
// ----- 外部URLを弾く処理
$defaultUrl = route('tasks.index');
$backUrl = $request->query('back_url', $defaultUrl);
// 外部URLブロック
if(!Str::startsWith($backUrl, config('app.url'))) {
$backUrl = $defaultUrl;
}
return view('tasks.show', compact('task', 'backUrl'));
}
3. 詳細→編集で back_url を引き継ぐ
// /resources/views/tasks/show.blade.php
<a href="{{ route('tasks.edit', ['task' => $task->id, 'back_url' => $backUrl ]) }}"
class=" text-white text-center bg-indigo-500 border-0 py-2 px-8 focus:outline-none hover:bg-indigo-600 rounded text-lg">
編集
</a>
4. 編集(edit)で showに戻るためのURLを作成
/app/Http/Controllers/TaskController.php
public function edit(Request $request, $id)
{
// ----- ユーザー情報取得
/** @var \App\Models\User $user */
$user = Auth::user();
// ----- タスク情報取得
$task = $user->tasks()
->with('taskCategory')
->findOrFail($id);
// ----- フォーカスマトリックス情報取得
$taskCategories = TaskCategory::get();
// ---- one-day or index への戻るボタン
$defaultUrl = route('tasks.index');
$backUrl = $request->query('back_url', $defaultUrl);
// 外部URLブロック
if(!Str::startsWith($backUrl, config('app.url'))) {
$backUrl = $defaultUrl;
}
// ----- showへ戻る専用URL(一覧URLを持ち回り)
$showUrl = route('tasks.show', ['task' => $task->id, 'back_url' => $backUrl]);
return view('tasks.edit', compact('task', 'taskCategories', 'backUrl', 'showUrl'));
}
5. 編集画面に「詳細へ戻る」リンクと更新フォーム
// /resources/views/tasks/edit.blade.php
<form action="{{ route('tasks.update', ['task' => $task->id]) }}" method="POST">
@csrf
@method('PUT')
<input type="hidden" name="back_url" value="{{ $backUrl ?? request('back_url') }}">
6. 更新後に show にリダイレクト(一覧URLを保持)
/app/Http/Controllers/TaskController.php
public function update(Request $request, $id)
{
// ----- ユーザー情報取得
/** @var \App\Models\User $user */
$user = Auth::user();
// ----- 時間
// フォームの date + time を結合
$startAt = Carbon::parse(
$request->start_date.' '.($request->start_time),
);
$endAt = Carbon::parse(
$request->end_date.' '.($request->end_time),
);
// 締切が開始より前ならエラー(after_or_equal相当)
if($endAt->lt($startAt)) {
return back()
->withErrors(['end_date' => '締切は開始以降にしてください。'])
->withInput();
}
// ----- タスク情報取得
$task = $user->tasks()
->findOrFail($id);
// ----- 保存
$task->update([
'user_id' => $user->id,
'task_category_id' => $request->task_category,
'title' => $request->title,
'description' => $request->description,
'start_at' => $startAt,
'end_at' => $endAt,
'is_completed' => $task->is_completed,
]);
// ----one-day or index への戻るボタン
$backUrl = $request->back_url;
// ----- リダイレクト
return to_route('tasks.show', ['task' => $task->id, 'back_url' => $backUrl])->with('success', 'タスクの更新完了しました。');
}
セキュリティ対策(外部URLブロック)
back_url はユーザーから渡される値なので、そのまま使うと危険。
オープンリダイレクトを防ぐため、アプリURLから始まるかをチェックする。
/app/Http/Controllers/TaskController.php
if(!Str::startsWith($backUrl, config('app.url'))) {
$backUrl = $defaultUrl;
}
// 以下で使用
// public function show(Request $request, $id)
// public function edit(Request $request, $id)