I have a page my.site.ru/tests/edit on this page, I have tests for users.
I have a single deletion of tests, next to each test there is a “Delete” button and when pressed everything happens correctly with a single deletion.
But I also have checkboxes for running several tests and then clicking on the “Delete selected” button I switch to “/tests/massDelete”
and there’s a 404 error page error.
Here are my routes :
Here is my controller :
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Test;
use App\Models\Question;
use App\Models\Answer;
use App\Models\Category;
use Auth;
class TestController extends Controller
{
public function index()
{
$tests = Auth::user()->tests;
return view('tests.index', compact('tests'));
}
public function create()
{
$categories = Category::all();
return view('tests.create', compact('categories'));
}
public function store(Request $request)
{
$request->validate([
'title' => 'required',
'description' => 'nullable',
'duration_hours' => 'required|integer|min:0',
'duration_minutes' => 'required|integer|min:0',
'duration_seconds' => 'required|integer|min:0',
'categories' => 'nullable|array',
'categories.*' => 'exists:categories,id',
]);
$test = new Test();
$test->title = $request->title;
$test->description = $request->description;
$test->user_id = Auth::id();
$test->duration_hours = $request->duration_hours;
$test->duration_minutes = $request->duration_minutes;
$test->duration_seconds = $request->duration_seconds;
$test->save();
if ($request->has('categories')) {
$test->categories()->sync($request->categories);
}
// Обработка вопросов и ответов
if ($request->has('questions')) {
foreach ($request->questions as $questionData) {
$question = new Question();
$question->test_id = $test->id;
$question->question = $questionData['question'];
$question->save();
if (isset($questionData['answers'])) {
foreach ($questionData['answers'] as $answerData) {
$answer = new Answer();
$answer->question_id = $question->id;
$answer->answer = $answerData['answer'];
$answer->is_correct = $answerData['is_correct'] ?? false;
$answer->save();
}
}
}
}
return redirect()->route('tests.edit', $test->id);
}
public function edit($id)
{
$test = Test::with('questions.answers', 'categories')->findOrFail($id);
$categories = Category::all();
return view('tests.edit', compact('test', 'categories'));
}
public function update(Request $request, $id)
{
$request->validate([
'title' => 'required',
'description' => 'nullable',
'duration_hours' => 'required|integer|min:0',
'duration_minutes' => 'required|integer|min:0',
'duration_seconds' => 'required|integer|min:0',
'categories' => 'nullable|array',
'categories.*' => 'exists:categories,id',
]);
$test = Test::findOrFail($id);
$test->title = $request->title;
$test->description = $request->description;
$test->duration_hours = $request->duration_hours;
$test->duration_minutes = $request->duration_minutes;
$test->duration_seconds = $request->duration_seconds;
$test->save();
if ($request->has('categories')) {
$test->categories()->sync($request->categories);
}
if ($request->has('questions')) {
foreach ($request->questions as $questionData) {
$question = Question::updateOrCreate(
['id' => $questionData['id'] ?? null, 'test_id' => $test->id],
['question' => $questionData['question']]
);
if (isset($questionData['answers'])) {
foreach ($questionData['answers'] as $answerData) {
Answer::updateOrCreate(
['id' => $answerData['id'] ?? null, 'question_id' => $question->id],
['answer' => $answerData['answer'], 'is_correct' => $answerData['is_correct'] ?? false]
);
}
}
}
}
return redirect()->route('tests.index');
}
public function allTests()
{
$tests = Auth::user()->tests()->withCount('questions')->get();
return view('tests.all', compact('tests'));
}
public function deleteQuestion($id)
{
$question = Question::findOrFail($id);
$question->answers()->delete(); // Удаляем все связанные ответы
$question->delete(); // Удаляем вопрос
return response()->json(['success' => true]);
}
public function delete($id)
{
$test = Test::findOrFail($id);
$test->questions()->delete();
$test->delete();
return response()->json(['success' => true]);
}
public function massDelete(Request $request)
{
$testIds = $request->input('selected_tests');
if (!empty($testIds)) {
foreach ($testIds as $id) {
$test = Test::findOrFail($id);
$test->questions()->delete();
$test->delete();
}
}
return redirect()->route('tests.index');
}
}
<h2>
{{ __('Все тесты') }}
</h2>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
<div class="p-6 text-gray-900">
<form id="delete-tests-form" method="POST" action="{{ route('tests.massDelete') }}">
@csrf
@method('DELETE')
<div class="mb-4">
<button type="submit" class="bg-red-500 text-white px-4 py-2 rounded">
Удалить выбранные
</button>
</div>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
@foreach ($tests as $test)
<div class="bg-white shadow-md rounded-lg p-4">
<input type="checkbox" name="selected_tests[]" value="{{ $test->id }}" class="mr-2">
<h3 class="text-lg font-semibold mb-2">{{ $test->title }}</h3>
<p class="mt-2 text-gray-600">{{ $test->description }}</p>
<p class="mt-2 text-gray-600">Количество вопросов: {{ $test->questions_count }}</p>
<a href="{{ route('tests.edit', $test->id) }}" class="mt-4 inline-block bg-blue-500 text-white px-4 py-2 rounded">
Редактировать
</a>
<button type="button" class="mt-4 inline-block bg-red-500 text-white px-4 py-2 rounded delete-single" data-id="{{ $test->id }}">
Удалить
</button>
</div>
@endforeach
</div>
</form>
</div>
</div>
</div>
</div>
document.addEventListener('DOMContentLoaded', function() { document.querySelectorAll('.delete-single').forEach(button => { button.addEventListener('click', function() { let testId = this.getAttribute('data-id'); if (confirm('Вы уверены, что хотите удалить этот тест?')) { fetch(`/tests/${testId}`, { method: 'DELETE', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content') } }) .then(response => response.json()) .then(data => { if (data.success) { location.reload(); } }); } }); }); });
Пробовал очищение кеша
Кирилл Иванов is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.