Laravel маршрутизация для удаления одной записи - PullRequest
0 голосов
/ 16 февраля 2020

Я новичок в Laravel (но не развиваюсь) и следую за бесплатным курсом Laravel 6 с нуля в Laracasts. Я не могу позволить себе подписаться на Laracasts, поэтому я не могу задавать вопросы там.

Я следил за тем, как инструктор создал приложение, которое перечисляло кучу статей, отображало одну статью, создавало и сохраняло новую статью, редактировало существующую статью и сохраняло ее обратно в базу данных. Сейчас я пытаюсь удалить отдельную запись, но не совсем понимаю, как это сделать.

На странице, где я отображаю одну запись, я даю пользователю возможность редактировать запись или удалять запись по двум отдельным ссылкам. Процесс редактирования работает нормально: он отображает запись, позволяет мне изменить ее (при условии, что я прошел проверки), а затем правильно сохраняет ее в базе данных.

Процесс удаления завершается неудачей. Поскольку я уже показываю запись пользователю и предположительно убедился, что это именно та запись, которую он хочет удалить, я хочу просто go для метода destroy () моего контроллера. Но я явно делаю это неправильно. Я думаю код в контроллере правильный, поэтому это могут быть испорченные маршруты. Курс не показывает вам, как сделать удаление видео и статей о переполнении стека, которые я видел, используют разные методы, ни один из которых я полностью не понимаю. Я надеюсь, что кто-то может сказать мне, что я делаю неправильно. Не может быть больше одной или двух неправильных строк ....

Вот сообщение, которое я получаю, когда нажимаю кнопку "Удалить" при отображении статьи № 6:

Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
http://localhost:8000/articles/6/delete 

Вот мой маршрут:

Route::get('/articles', 'ArticlesController@index');
Route::post('/articles', 'ArticlesController@store');
Route::get('/articles/create', 'ArticlesController@create');
Route::get('/articles/{article}', 'ArticlesController@show');
Route::get('/articles/{article}/edit', 'ArticlesController@edit');
Route::put('/articles/{article}', 'ArticlesController@update');
Route::post('/articles/{article}/delete', 'ArticlesController@destroy');

Вот страница, которая отображает статью и позволяет пользователю нажимать на ссылку Изменить или Удалить ссылки:

@extends ('layout');

@section ('content');

<div id="wrapper">
<div id="page" class="container">
    <div id="content">
        <div class="title">
            <h2>{{ $article->title }}</h2>
            <span class="byline">{{ $article->author}}</span></div>
        <p><img src="{{ $article->photopath}}" alt="" class="image image-full" /> </p>
        <p>{{ $article->body }}
        <p><a class="article-link" href="/articles/{{ $article->id }}/edit">Edit This Article</a>&nbsp;&nbsp;&nbsp;
        <a class="article-link" href="/articles/{{ $article->id }}/delete">Delete This Article</a></p>  
    </div>
</div>
</div>
@endsection

Наконец, вот мой ArticleController:

<?php

namespace App\Http\Controllers;

use App\Article;
use Illuminate\Http\Request;

class ArticlesController extends Controller
{
public function index()
{
    $articles = Article::latest()->paginate(2);
    return view ('articles.index', ['articles' => $articles]);
}

public function show(Article $article) 
{
    return view('articles.show', ['article' => $article]);
}

public function create() 
{
    return view('articles.create');
}

public function store() 
{
    //Stores a NEW article
    Article::create($this->validateArticle());
    return redirect('/articles');
}   

public function edit(Article $article) 
{
    return view('articles.edit', ['article' => $article]);
}

public function update(Article $article)
{
    //Updates an EXISTING article
    $article->update($this->validateArticle());
    return redirect('/articles/'.$article->id);
}

public function validateArticle()
{
    return request()->validate([
        'title' => ['required', 'min:5', 'max:20'],
        'author' => ['required', 'min:5', 'max:30'],
        'photopath' => ['required', 'min:10', 'max:100'],
        'excerpt' => ['required', 'min:10', 'max:50'],
        'body' => ['required', 'min:50', 'max:500']
    ]);
}

public function delete(Article $article)
{
    return view('articles.delete', ['article' => $article]);
}

public function destroy(Article $article)
{
    $article = Article::find($article->id);
    $article->delete();
    return redirect('/articles');
}
}

Ответы [ 4 ]

1 голос
/ 16 февраля 2020

Фасад \ Ignition \ Exceptions \ ViewException Маршрут [article.destroy] не определен. (Представление: C: \ Laravel \ proj01 \ resources \ views \ article \ show.blade. php)

Убедитесь, что у вас есть маршруты с именем

, когда вы используйте что-нибудь вроде: route('some.route.name') должен быть маршрут с соответствующим названием.

В вашей сети я не вижу, чтобы вы называли свои маршруты.

Route::get('/articles', 'ArticlesController@index');
Route::post('/articles', 'ArticlesController@store');
Route::get('/articles/create', 'ArticlesController@create');
Route::get('/articles/{article}', 'ArticlesController@show');
Route::get('/articles/{article}/edit', 'ArticlesController@edit');
Route::put('/articles/{article}', 'ArticlesController@update');
Route::post('/articles/{article}/delete', 'ArticlesController@destroy')->name('article.destroy');

Обратите внимание на ->name('article.destroy');

1 голос
/ 16 февраля 2020
// Blade file
@extends('layouts.backend.app')

@section('title','Article')

@push('css')
<link href="{{ asset('backend/plugins/jquery-datatable/skin/bootstrap/css/dataTables.bootstrap.css') }}" rel="stylesheet">
@endpush
@section('content')
<div class="container-fluid">
    <div class="block-header">
        <h2>
        <a class="btn btn-info" href="{{ route('admin.tag.create') }}">
            <i class="material-icons">add</i>
        {{ __('ADD ARTICLE') }}
        </a>            
        </h2>
    </div>

    <!-- Exportable Table -->
    <div class="row clearfix">
        <div class="col-lg-12 col-md-12 col-sm-12 col-xs-12">
            <div class="card">
                <div class="header">
                    <h2>
                        <a href="{{ route('admin.tag.index') }}">
                            {{ __('ALL ARTICLE') }}
                            <span class="btn btn-warning sm">{{ $articles->count() }}</span>
                        </a>
                    </h2>
                </div>
                <div class="body">
                    <div class="table-responsive">
                        <table class="table table-bordered table-striped table-hover dataTable js-exportable">
                            <thead>
                                <tr>
                                <th>{{__('Sl')}}</th>
                                <th>{{__('Name')}}</th>
                                <th>{{__('Slug')}}</th>
                                <th>i{{__('Post Count')}}</th>
                                <th>{{__('Create At')}}</th>
                                <th>{{__('Action')}}</th>
                            </tr>
                            </thead>
                            <tfoot>
                                <tr>
                                    <th>{{__('Sl')}}</th>
                                    <th>{{__('Name')}}</th>
                                    <th>{{__('Slug')}}</th>
                                    <th>{{__('Post Count')}}</th>
                                    <th>{{__('Create At')}}</th>
                                    <th>{{__('Action')}}</th>
                                </tr>
                            </tfoot>
                            <tbody>
                               @if(Auth::check() && Auth::user()->role->id == 1)
                                   @foreach($articles as $key=>$article)
                                       <tr>
                                           <td>{{ $key + 1 }}</td>
                                           <td>{{ $article->name }}</td>
                                           <td>{{ $article->slug }}</td>
                                           <td>{{ $article->posts->count() }}</td>
                                           <td>{{ $article->created_at->diffForHumans() }}</td>
                                           <td >
                                               <a href="{{ route('admin.$article.edit',$article->id) }}" class="btn btn-info waves-effect">
                                                   <i class="material-icons">edit</i>
                                               </a>
                                               <button class="btn btn-danger waves-effect" type="button" onclick="deletearticle({{ $article->id }})">
                                                   <i class="material-icons">delete</i>
                                               </button>
                                               <form id="delete-form-{{ $article->id }}" action="{{ route('admin.article.destroy',$article->id) }}" method="POST" style="display: none;">
                                                   @csrf
                                                   @method('DELETE')
                                               </form>
                                           </td>
                                       </tr>
                                   @endforeach
                                @else
                                @endif
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- #END# Exportable Table -->
</div>
@endsection


@push('js')
<script src="{{asset ('backend/plugins/jquery-datatable/jquery.dataTables.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/skin/bootstrap/js/dataTables.bootstrap.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/dataTables.buttons.min.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/buttons.flash.min.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/jszip.min.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/pdfmake.min.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/vfs_fonts.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/buttons.html5.min.js') }}"></script>
<script src="{{asset ('backend/plugins/jquery-datatable/extensions/export/buttons.print.min.js') }}"></script>
<script src="{{ asset('backend/js/pages/tables/jquery-datatable.js') }}"></script>
<script src="https://unpkg.com/sweetalert2@7.19.1/dist/sweetalert2.all.js"></script>

<script type="text/javascript">
    function deletearticle(id) {
        swal({
            title: 'Are you sure?',
            text: "You won't be able to revert this!",
            type: 'warning',
            showCancelButton: true,
            confirmButtonColor: '#3085d6',
            cancelButtonColor: '#d33',
            confirmButtonText: 'Yes, delete it!',
            cancelButtonText: 'No, cancel!',
            confirmButtonClass: 'btn btn-success',
            cancelButtonClass: 'btn btn-danger',
            buttonsStyling: false,
            reverseButtons: true
        }).then((result) => {
            if (result.value) {
                event.preventDefault();
                document.getElementById('delete-form-'+id).submit();
            } else if (
                // Read more about handling dismissals
                result.dismiss === swal.DismissReason.cancel
            ) {
                swal(
                    'Cancelled',
                    'Your data is safe :)',
                    'error'
                )
            }
        })
    }
</script>
@endpush

//  web.php 
Route::group(['as'=>'admin.','prefix'=>'admin','namespace'=>'Admin','middleware'=>['auth','admin']], function (){
    Route::get('dashboard','DashboardController@index')->name('dashboard');
    Route::resource('article','ArticleController');

});
// Controller file 
<?php

namespace App\Http\Controllers\Admin;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Brian2694\Toastr\Facades\Toastr;
use App\Article;
class TagController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $articles = Article::latest()->get();
        return view('admin.article.index',compact('articles'));
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        return view('admin.article.create');
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $this->validate($request,[
            'name' => 'required|unique:articles'
        ]);
        $article = new Article();
        $article->name = $request->name;
        $article->slug = str_slug($request->name);
        $article->save();
        Toastr::success('Article Successfully Saved :)','Success');
        return redirect()->route('admin.article.index');
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        $tag = Article::find($id);
        return view('admin.article.edit',compact('article'));
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $this->validate($request,[
            'name' => 'required'
        ]);

        $article = Article::find($id);
        $article->name = $request->name;
        $article->slug = str_slug($request->name);
        $article->save();
        Toastr::success('Article Successfully Updated','Success');
        return redirect()->route('admin.article.index');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        Article::find($id)->delete();
        Toastr::success('Article Successfully Deleted',"Success");
        return redirect()->back();
    }
}
1 голос
/ 16 февраля 2020
        Route::post('/articles/{id}/delete', 'ArticlesController@destroy')->name('article.destroy');

        public function destroy($id)
        {
            $article = Article::find($id);
            $article->delete();
            return redirect('/articles');
        }

<a class="article-link" href="{{ route('article.destroy',$article->id) }}">Delete This Article</a></p>  

 <form id="delete-form-{{ $article->id }}" action="{{ route('article.destroy',$article->id) }}" method="POST" style="display: none;">
     @csrf
     @method('DELETE')
 </form>
0 голосов
/ 20 февраля 2020

Прежде всего, спасибо обоим респондентам. Ни один из ответов полностью не решил мою проблему, но вы оба помогли мне go в лучшем направлении. Я награждаю Md. Галочкой выбранного ответа, потому что он, вероятно, приблизил меня.

Вот мой наконец код с несколькими замечаниями.

Во-первых, вот мои маршруты. Критическое изменение здесь состоит в том, что маршрут, который приводит меня к методу уничтожения, должен использовать DELETE, а не POST:

Route::get('/articles', 'ArticlesController@index');
Route::post('/articles', 'ArticlesController@store');
Route::get('/articles/create', 'ArticlesController@create');
Route::get('/articles/{article}', 'ArticlesController@show');
Route::get('/articles/{article}/edit', 'ArticlesController@edit');
Route::put('/articles/{article}', 'ArticlesController@update');
Route::delete('/articles/{id}/delete', 'ArticlesController@destroy')->name('article.destroy');

Окончательная версия ArticlesController:

<?php

namespace App\Http\Controllers;

use App\Article;
use Illuminate\Http\Request;

class ArticlesController extends Controller
{
public function index()
{
    $articles = Article::latest()->paginate(5);
    return view ('articles.index', ['articles' => $articles]);
}

public function show(Article $article) 
{
    return view('articles.show', ['article' => $article]);
}

public function create() 
{
    return view('articles.create');
}

public function store() 
{
    //Stores a NEW article
    Article::create($this->validateArticle());
    return redirect('/articles');
}   

public function edit(Article $article) 
{
    return view('articles.edit', ['article' => $article]);
}

public function update(Article $article)
{
    //Updates an EXISTING article
    $article->update($this->validateArticle());
    return redirect('/articles/'.$article->id);
}

public function validateArticle()
{
    return request()->validate([
        'title' => ['required', 'min:5', 'max:30'],
        'author' => ['required', 'min:5', 'max:30'],
        'photopath' => ['required', 'min:10', 'max:100'],
        'excerpt' => ['required', 'min:10', 'max:50'],
        'body' => ['required', 'min:50', 'max:500']
    ]);
}

public function delete(Article $article)
{
    return view('articles.delete', ['article' => $article]);
}

public function destroy($id)
{
    $article = Article::find($id);
    $article->delete();
    return redirect('/articles');
}
}

final view использует метод post в форме, но переопределяет его для удаления с помощью директивы @method ('DELETE'), и, конечно, директива @csrf также должна быть там:

@extends ('layout');

@section ('content');

<div id="wrapper">
<div id="page" class="container">
    <div id="content">
        <div class="title">
            <h2>{{ $article->title }}</h2>
            <span class="byline">{{ $article->author}}</span></div>
        <p><img src="{{ $article->photopath}}" alt="An image" class="image image-full"/></p>
        <p style="font-style: italic">{{ $article->excerpt }}</p>
        <p>{{ $article->body }}</p>
        <div>           
            <a class="btn btn-warning" href="/articles/{{ $article->id }}/edit">Edit This Article</a>
            <form method="post" class="delete_form" action="{{ route('article.destroy', $article->id) }}">
                @csrf
                @method('DELETE')
                <button type="submit" class="btn btn-danger">Delete This Article</button>
            </form>             
        </div>
    </div>
</div>
</div>
@endsection
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...