Laravelでresourceを使ってCRUD機能を爆速で開発する方法

こんにちは、JeffTechです。

# この記事で実現できること
- Route::resourceの使い方
- Controllerをphp artisanの--resourceオプションで作成する
- CRUD機能を少ない工数で開発する

# 説明
今回はリソースコントローラというLaravelの便利機能を使って、CRUD機能を爆速で開発します。
今までcreateやshow、editなどのルーティングを一つ一つしていた方にもわかるように、丁寧に説明していきます。

この記事では、テーブルの作成（マイグレーションの実行）から説明します。Laravelの環境構築やデータベースとの接続方法等は説明していませんので、まずはLaravelのインストールとデータベースとの接続をしてください。
私はLaravelのプロジェクト名とデータベース名をlaravel_base_resourceにしていますでの、合わせるとわかりやすいかもしれません。

それでは行ってみましょう！

# 開発環境
- OS： MacOS Catalina
- PHP： 7.3
- Laravel： 6.2
- MySQL: 5.7

# 実装の流れ
1. Articleモデルとマイグレーションファイルの作成
2. Articlesテーブル作成
3. Articleモデルの編集
4. テストデータの作成
5. Controllerの作成
6. Routeの編集
7. 記事一覧画面実装
8. 記事投稿機能実装
9. 記事詳細画面実装
10. 記事編集機能実装
11. 削除機能実装
12. ルーティングの見直し






# 実装
## Articleモデルとマイグレーションファイルの作成
Laravelのプロジェクトフォルダでartisanコマンドでモデルとマイグレーションファイルの作成を行います。

```bash:ターミナル
$ php artisan make:model Models/Article -m
```
これで`app/Models/Article.php`というモデルと`database/migrations`にarticlesテーブルを作成するためのマイグレーションファイルが作成されました。
※マイグレーションのファイル名は`作成した年_作成した月_作成した日_作成時間_create_articles_table.php`という名前になります。私の場合は、`2021_03_07_165441_create_articles_table.php`となっています。

モデルはデータベースとのやり取りを行う機能等を司るファイルです。
マイグレーションファイルはテーブルに関する操作をすることができます。


## Articlesテーブル作成
それでは作ったマイグレーションファイルでテーブル定義を書いていきます。

```php:2021_03_07_165441_create_articles_table.php
<?php

ー省略ー

class CreateArticlesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('articles', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('title', 100); // ここを追加
            $table->text('body'); // ここを追加
            $table->integer('status'); // ここを追加
            $table->timestamps();
        });
    }
    
    ー省略ー
    
}
```
これで記事の`title(タイトル)`と`body(内容)`、`status(状態)`を保存するためのarticlesテーブルのマイグレーションファイルが完成しました。
早速データベースに反映させていきます。

```bash:ターミナル
$ php artisan migrate
```
`Migration table created successfully`となっていれば大丈夫です。
`articlesテーブル`に混じって`usersテーブル`や`password_resetsテーブル`なども作られています。これはLaravelをインストールした時に、元からあるマイグレーションファイルが実行されたために作成されただけなので、特に気にしなくて大丈夫です。
エラーが出ている場合は、データベースとの接続がうまくいっていないか、マイグレーションファイルに誤りがあるなどの原因が考えられるので、一度確認してみてください。

## Articleモデルの編集
今回の場合は`Articlesテーブル`の`title`と`body`、`status`の内容をデータベースに保存したいので、下記のように`app/Models/Article.php`を編集してください。

```php:Article.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Article extends Model
{
    ーーここから追加ーー
    protected $fillable = [
        'title',
        'body',
        'status',
    ];
    ーーここまで追加ーー
}
```
`protected $fillable = ['カラム名']`とすることで、指定したカラムのデータがデータベースで更新できるようになります。

## テストデータの作成
### 1. Factoryを作る
テストデータの作成はSeederのみで作成できますが、今回は練習という意味も含めてFactoryを使用して作っていきます。Seederだけで書く場合は1つ1つデータを作っていきますが、Factoryを組み合わせると、いくつものテストデータを自動で作ってくれるのでとても便利です。
下記のコードを実行して、Factoryを作成してください。

```bash:ターミナル
$ php artisan make:Factory ArticleFactory
```
`database/factories/ArticleFactory.php`が作成されていれば完璧です。

FactoryはFakerを使用してテストデータの作成をするのですが、デフォルトで挿入されるデータが英語なので、`config/app.php`を変更して日本語化していきます。

```php:app.php
<?php

return [

    ー省略ー

    'timezone' => 'Asia/Tokyo',

    ー省略ー

    'locale' => 'ja',
    
    ー省略ー

    'fallback_locale' => 'ja',
    
    ー省略ー

    'faker_locale' => 'ja_JP',

    ー省略ー
];
```
ついでなので、タイムゾーン等も一緒に変えましたが、`faker_locale => 'ja_JP'`になっていれば大丈夫です。

日本語化が完了したので、データの追加処理をFactoryに記述していきます。
`database/factories/ArticleFactory.php`を下記の通り編集してください。

```php:ArticleFactory.php
<?php

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Models\Article; // ここを変更
use Faker\Generator as Faker;

$factory->define(Article::class, function (Faker $faker) { // ここを変更
    return [
        ーーここから追加ーー
        'title' => $faker->word,
        'body' => $faker->realText,
        'status' => $faker->numberBetween(0, 1),
        'created_at' => now(),
        'updated_at' => now(),
        ーーここまで追加ーー
    ];
});
```
`$faker->`とすることで様々なデータを挿入することができます。
`now()`はLaravelのヘルパ関数で、現在時刻を取得してくれます。
このFactoryファイルでは、`title`にランダムな単語、`body`に適当な文章、`status`には0か1、`created_at`と`updated_at`には現在時刻が入るように設定しています。

Fakerではそれ以外にも様々なデータを挿入できますので、今回扱ったもの以外を使いたいときは、[こちらを参考にしてください。](https://qiita.com/tosite0345/items/1d47961947a6770053af)


### 2. Seederを作る
次に、Seederを下記のコマンドで作成してください。

```bash
$ php artisan make:seeder ArticleTableSeeder
```
`database/seeds/ArticleTableSeeder`が作成されます。

runメソッドの中を編集していきます。

```php:ArticleTableSeeder.php
<?php

use Illuminate\Database\Seeder;

class ArticleTableSeeder extends Seeder
{
    public function run()
    {
        factory(App\Models\Article::class, 100)->create(); //ここを追加
    }
}
```
ArticlesテーブルにFactoryで作成した100のデータを追加するようにしています。

### 3. DatabaseSeeder.phpの更新
Seederを使うために`database/seeds/DatabaseSeeder.php`に作成したシーダークラスを定義します。

```php:DatabaseSeeder.php
<?php

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(ArticleTableSeeder::class); // ここを追加
    }
}

```
### 4. db:seedの実行
ここまで作成できたら、artisanコマンドでシーダーを実行します。

```bash
$ php artisan db:seed
```
これで、`title`は英語ですが`body`は日本語のテキストがDBに反映されています。Fakerの日本語化をしましたが、日本語になるものとならないものがあるので、気をつけてください。
`status`には0か1の数字がフラグとして入っています。

## Controllerの作成
ここまででテストデータを作成したので、次はコントローラを作成し、CRUD処理の記述をしていきたいと思います。

```bash
$ php artisan make:controller ArticleController --resource
```
artisanコマンドでコントローラを作成する際に、`--resource`オプションをつけると、簡単にリソースコントローラを作成することができます。
`app/Http/Controllers/ArticleController.php`が作成されていることを確認して、中身を見てみましょう。

```php:ArticleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ArticleController extends Controller
{
    public function index()
    {
        //
    }

    public function create()
    {
        //
    }

    public function store(Request $request)
    {
        //
    }

    public function show($id)
    {
        //
    }

    public function edit($id)
    {
        //
    }

    public function update(Request $request, $id)
    {
        //
    }

    public function destroy($id)
    {
        //
    }
}
```
最初からindexメソッドやcreateメソッドなどが作成されていることがわかりますね。
これを編集していけば、簡単にCRUD機能が実装できるようになっています。

## Routeの編集
ルーティングも簡単に行うことができるようになっています。
`routes/web.php`を下記の通り編集してください。

```php:web.php
<?php

Route::resource('articles', 'ArticleController');
```
たった一行だけです。他に何もいりません。
ターミナルで`$ php artisan route:list`と叩いてルーティング確認すると、下記のようになっています。

```
+--------+-----------+-------------------------+------------------+------------------------------------------------+--------------+
| Domain | Method    | URI                     | Name             | Action                                         | Middleware   |
+--------+-----------+-------------------------+------------------+------------------------------------------------+--------------+
|        | GET|HEAD  | articles                | articles.index   | App\Http\Controllers\ArticleController@index   | web          |
|        | POST      | articles                | articles.store   | App\Http\Controllers\ArticleController@store   | web          |
|        | GET|HEAD  | articles/create         | articles.create  | App\Http\Controllers\ArticleController@create  | web          |
|        | GET|HEAD  | articles/{article}      | articles.show    | App\Http\Controllers\ArticleController@show    | web          |
|        | PUT|PATCH | articles/{article}      | articles.update  | App\Http\Controllers\ArticleController@update  | web          |
|        | DELETE    | articles/{article}      | articles.destroy | App\Http\Controllers\ArticleController@destroy | web          |
|        | GET|HEAD  | articles/{article}/edit | articles.edit    | App\Http\Controllers\ArticleController@edit    | web          |
+--------+-----------+-------------------------+------------------+------------------------------------------------+--------------+
```
Laravelは最初から`URIがapi/user`というものがルーティングされていますが、今回は関係ないので上記の`$ php artisan route:list`の表示結果からは外しています。

各メソッドの機能は下記の通りです。

※表1
| メソッド名 | 機能 |
|:-:|:-:|
| index | 記事一覧表示 |
| store | 記事投稿処理 |
| create | 記事投稿画面表示 |
| show | 記事詳細表示 |
| update | 記事編集処理 |
| destroy | 記事削除処理 |
| edit | 記事編集画面表示 |


## 記事一覧画面実装
メソッドはindex(記事一覧表示)を使用していきます。
わからない方は各メソットがどのような処理を担当しているかの表である※表1を参考にしてください。
ちなみにルーティングを確認するコマンドは`$ php artisan route:list`です。

### 1. controllerの編集
先程作成した`app/Http/Controllers/ArticleController.php`を下記の通り編集してください。

```php:ArticleController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Article; // ここを追加

class ArticleController extends Controller
{
    public function index()
    {
        // すべての記事を取得
        $articles = Article::all(); // ここを追記

        // 記事一覧を表示
        return view('articles.index', compact('articles')); // ここを追記
    }
```
これで`http://127.0.0.1:8000/articles`にアクセスした時に、`ArticleController`のindexメソッドが走り、すべての記事データを取得してから記事一覧画面に遷移するような実装できました。
細かく見ていくと、`$articles = Article::all();`でArticlesテーブルからデータを取得し、`return view('articles.index', compact('articles'));`で
`resources/views/articles/index.blade.php`というビューにArticlesテーブルのデータが渡される処理を記述していることがわかります。

### 2. viewの作成
今回はCSSをあまり使いたくないのでviewの作成前にBootstrapを導入していきます。
導入といっても、下の3つのコマンドを叩くだけです。

```
$ composer require laravel/ui:^1.0 --dev
$ php artisan ui bootstrap --auth
$ npm install && npm run dev
```
Bootstrapの導入がよくわからない方は[こちらも参考にしてください。](https://qiita.com/crispypanda/items/903c33ba35b725852a81)

Bootstrapの導入が終わった方は、`resources/views`配下に`articlesディレクトリ`を作成してください。
下記コマンドで作成しても大丈夫ですし、GUIで作成しても構いません。

```bash
$ mkdir resources/views/articles
```
作成できたら、`resources/views/articles`配下に`index.blade.php`を作成して編集してください。

```bash
$ touch resources/views/articles/index.blade.php
```

```html:index.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
  <div class="row justify-content-center">
    <div class="col-md-12">
      <div class="card">
        <div class="card-header">投稿一覧</div>

        <div class="card-body">
          <div class="table-resopnsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>タイトル</th>
                  <th>本文</th>
                  <th>状態</th>
                </tr>
              </thead>
              <tbody>
                @if(isset($articles))
                @foreach ($articles as $article)
                <tr>
                  <td>{{ $article->title }}</td>
                  <td>{{ $article->body }}</td>
                  <td>{{ $article->status }}</td>
                </tr>
                @endforeach
                @endif
              </tbody>
            </table>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
@endsection
```
コントローラで渡したすべての記事データが入っている`$articles`を`foreach`のループ処理で一つ一つ切り分けて画面に表示しています。

## 記事投稿機能実装
メソッドはcreate(記事投稿画面表示)とstore(記事投稿処理)を使用していきます。
それって何だっけの人は、記事一覧画面実装の最初の部分を見てみてください。

### 1. 一覧ページに投稿ボタンの設置
一覧画面から投稿画面に遷移したいので、一覧画面に投稿ボタンを設置します。
`resources/views/articles/index.blade.php`を下記の通り編集してください。

```html:index.blade.php
@extends('layouts.app')

@section('content')

        ーー省略ーー

        <div class="card-header">投稿一覧</div>

        <div class="card-body">

          ーーここから追加ーー
          <button type="button" class="btn btn-primary mb-3 d-block w-100" onclick="location.href='{{ route('articles.create') }}'">
            新規投稿
          </button>
          ーーここまで追加ーー

          <div class="table-resopnsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>記事No.</th>
                  <th>タイトル</th>
                  <th>本文</th>
                  <th>状態</th>
                </tr>
              </thead>

              ーー省略ーー
@endsection
```
`onclick="location.href='{{ route('articles.create') }}'"`とすることで、ボタンをクリックすると記事投稿画面に遷移するようにしています。

### 2. 記事投稿画面を表示させる
記事を投稿するための投稿画面を実装していきます。
`app/Http/Controllers/ArticleController.php`を下記の通り編集してください。

```php:ArticleController.php
// createメソッドの部分だけ抜粋しています
public function create()
{
        // 投稿画面表示
        return view('articles.create'); // ここを追記
}
```
ただ投稿画面を表示させるだけなので、単純にこれから作成するビューファイルの`resources/views/articles/create.blade.php`を返せばOKです。

次に`create.blade.php`を作成していきます。

```bash
$ touch resources/views/articles/create.blade.php
```

```html:create.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-12">
            <div class="card">
                <div class="card-header">新規投稿</div>
                <div class="card-body">
                    <form action="{{ route('articles.store') }}" method="POST">
                        @csrf
                        <div class="form-group row">
                            <label for="title" class="col-md-2 col-form-label text-md-right">タイトル</label>
                            <div class="col-md-9">
                                <input id="title" type="text" class="form-control" name="title" value="{{ old('title') }}">
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="body" class="col-md-2 col-form-label text-md-right">本文</label>
                            <div class="col-md-9">
                                <textarea name="body" id="body" style="resize: none; height: 200px; width: 100%">{{ old('body') }}</textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <label class="col-md-2 col-form-label text-md-right">ステータス</label>
                            <div class="form-check form-check-inline ml-3">
                                <input class="form-check-input" type="radio" id="open" name="status" value="0" checked="checked">
                                <label class="form-check-label" for="open">公開</label>
                             </div>
                             <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" id="private"  name="status" value="1">
                                <label class="form-check-label" for="private">未公開</label>
                             </div>
                        </div>
                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="button" class="btn btn-secondary" onClick="history.back()">戻る</button>
                                <button type="submit" class="btn btn-primary ml-3" name='action' value='add'>
                                    投稿
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```
これで新規投稿のビューファイルが完成しました。
注意点として、`@csrf`というものがformタグのあとにありますが、セキュリティの貧弱性であるCSRFにこれ一文字で対策できるスグレモノです。
Laravelではformタグの中に`@csrf`がないとsubmitできないので、絶対に記述しましょう！

### 3. 記事投稿の処理を実装する
`app/Http/controllers/ArticleController.php`のstoreメソッドで新規投稿をできるようにしていきたいので、storeメソッドを編集していきます。

```php:ArticleController.php
// storeメソッドの部分だけ抜粋しています
public function store(Request $request)
{
    // 投稿内容保存処理
    $article = Article::create([
        'title' => $request->title,
        'body' => $request->body,
        'status' => $request->status,
    ]); // ここを追加

    return redirect()->route('articles.index'); // ここを追加
}
```
`$request`という変数でフォームの入力内容を受け取り、Articleモデルを介してフォームの入力内容をArticlesテーブルに登録しています。
また、投稿完了後はトップページに戻るようにしています。


## 記事詳細画面実装
メソッドはshow(記事詳細画面表示)を使用していきます。
それって何だっけの人は、記事一覧画面実装の最初の部分を見てみてください。

### 1. 記事一覧画面のタイトルに詳細画面を表示させるためのリンクを追加
記事一覧画面のタイトルに詳細画面へのリンクを貼り、タイトルをクリックしたら、クリックした記事の詳細を表示させる画面に遷移させていこうと思います。
まずは`resources/views/articles/index.blade.php`にリンクを追加していきます。

```html:index.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <table class="table table-striped">
        <thead>
            <tr>
                <th>タイトル</th>
                <th>本文</th>
                <th>状態</th>
            </tr>
        </thead>
        <tbody>
            @if(isset($articles))
            @foreach ($articles as $article)
            <tr>
                    <td><a href="{{ route('articles.show', $article->id) }}">{{ $article->title }}</a></td> // ここを編集
                    <td>{{ $article->body }}</td>
                    <td>{{ $article->status }}</td>
            </tr>
            @endforeach
            @endif
        </tbody>
    </table>
ーー省略ーー

</div>
@endsection
```
`href={{ route('articles.show', $article->id) }}`に注目してください。
まず、`articles.show`というルーティングに飛ばされ、`article.show`のURIは、`articles/{article}`となっているので、第2引数の`$article->id`が`{article}`の部分に入るようになります。よって、localhost/articles/記事IDというURLに飛ばされることになります。

### 2. 記事編集フォームを表示させる
`app/Http/Controllers/ArticleController.php`のshowメソッドを下記のように編集してください。

```php:ArticleController.php
// showメソッドの部分のみ抜粋
public function show(Int $id)
{
    // ビューから渡されたIDの記事を取得
    $article = Article::find($id);

    // 記事詳細画面を表示
    return view('articles.show', compact('article'));
}
```
`$article = Article::find($id);`でビューから渡された記事IDに紐付いた記事データをArticlesテーブルから取得しています。
その取得したデータを詳細画面のビューに渡しています。

ビューファイルも合わせて作っちゃいましょう。

```bash
$ touch resources/views/articles/show.blade.php
```

```html:show.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
  <div class="row justify-content-center">
    <div class="col-md-12">
      <div class="card">
        <div class="card-header">記事詳細</div>

        <div class="card-body">
          <div class="table-resopnsive">
            <table class="table table-striped">
              <thead>
                <tr>
                  <th>タイトル</th>
                  <th>本文</th>
                  <th>状態</th>
                </tr>
              </thead>
              <tbody>
                @if(isset($article))
                <tr>
                  <td>{{ $article->title }}</a></td>
                  <td>{{ $article->body }}</td>
                  <td>{{ $article->status }}</td>
                </tr>
                @endif
              </tbody>
            </table>
            @if(isset($article))
            <div class="text-center">
                <button type="button" class="btn btn-secondary" onClick="history.back()">戻る</button>
                <button type="button" class="btn btn-primary ml-3" onClick="location.href='{{ route('articles.edit', $article->id) }}'">
                    編集
                </button>
            </div>
            @endif
          </div>
        </div>
      </div>
    </div>
  </div>
</div>
@endsection
```
記事一覧画面の記事タイトルをクリックすると記事詳細がこれで表示さるようになりました。
また、ブラウザバックのための戻るボタンと次に実装していく記事編集画面に行くための編集ボタンも設置しています。


## 記事編集機能実装
メソッドはedit(画面表示)とupdate(編集処理)を使用していきます。
それって何だっけの人は、記事一覧画面実装の最初の部分を見てみてください。

### 1. 記事編集画面を表示させる
`app/Http/Controllers/ArticleController.php`を下記の通り編集してください。

```php:ArticleController.php
// editメソッドの部分のみ抜粋
public function edit(Int $id)
{
    // ビューから渡されたIDの記事を取得
    $article = Article::find(Int $id); // ここを追記

    // 記事編集画面を表示
    return view('articles.edit', compact('article')); // ここを追記
}
```
編集したい記事のデータを`edit.blade.php`に渡したいだけなので、詳細画面を表示させるためのshowメソッドとコードはほとんど同じです。

`edit.blade.php`を作成していきましょう。

```bash
$ touch resources/views/articles/edit.blade.php
```

```html:edit.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-12">
            <div class="card">
                <div class="card-header">新規投稿</div>
                <div class="card-body">
                    <form action="{{ route('articles.update', $article->id) }}" method="POST">
                        @csrf
                        <div class="form-group row">
                            <label for="title" class="col-md-2 col-form-label text-md-right">タイトル</label>
                            <div class="col-md-9">
                                <input id="title" type="text" class="form-control" name="title" value="{{ old('title', $article->title) }}">
                            </div>
                        </div>
                        <div class="form-group row">
                            <label for="body" class="col-md-2 col-form-label text-md-right">本文</label>
                            <div class="col-md-9">
                                <textarea name="body" id="body" style="resize: none; height: 200px; width: 100%">{{ old('body', $article->body) }}</textarea>
                            </div>
                        </div>
                        <div class="form-group row">
                            <label class="col-md-2 col-form-label text-md-right">ステータス</label>
                            <div class="form-check form-check-inline ml-3">
                                <input class="form-check-input" type="radio" id="open" name="status" value="0" {{ $article->status === 0 ? 'checked' : null }}>
                                <label class="form-check-label" for="open">公開</label>
                             </div>
                             <div class="form-check form-check-inline">
                                <input class="form-check-input" type="radio" id="private"  name="status" value="1" {{ $article->status === 1 ? 'checked' : null }}>
                                <label class="form-check-label" for="private">未公開</label>
                             </div>
                        </div>
                        <div class="text-center">
                            <button type="button" class="btn btn-secondary" onClick="history.back()">戻る</button>
                            <button type="submit" class="btn btn-primary ml-3" name='action' value='add'>
                                編集
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
```
編集フォームなので、投稿フォームである`create.blade.php`とほとんど同じです。
`value="{{ old('title', $article->title) }}"`としていますが、第2引数の`$article->title`が初期値に指定されています。そのため、編集フォームの中にはじめから選択した記事のタイトルが入っていることになります。
また、ラジオボタンの初期値を設定するために、`{{ $article->status === 0 ? 'checked' : null }}`という記述を追加しています。これは、条件演算子を使って記事ステータスが0のときは`checked`を追加し、0以外のときは何もしないという処理になっています。

### 2. 記事編集処理の実装
storeメソッドと似ていますが、投稿ではなく編集なので、fill+saveメソッドを使用していきます。編集処理はsaveメソッド以外にもupdateメソッドというものがありますが、saveメソッドは差分保存でupdateメソッドはまるっと全部保存という違いがあります。つまり、saveメソッドは何か変更が加えられたときのみ処理が走るのに対して、updateはデータが変更されてようが、されてなかろうが更新してしまいます。今回は差分だけ保存できればいいので、saveを使用して行きます。
それでは`app/Http/Controllers/ArticleController.php`を編集していきます。

```php:ArticleController.php
// updateメソッドの部分のみ抜粋
public function update(Request $request, Int $id)
{
    // 選択された記事データを取得
    $article = Article::find($id);

    // 編集処理実行
    $article->fill($request->all())->save();

    // 記事一覧画面へ
    return redirect()->route('articles.index');
}
```


## 削除機能実装
メソッドはdestroy(記事削除処理)を使用していきます。
それって何だっけの人は、記事一覧画面実装の最初の部分を見てみてください。

### 1. 削除ボタンの配置
削除ボタンは記事詳細画面に設置するので、`resources/articles/show.blade.php`を下記の通り編集してください。

```html:show.blade.php
@extends('layouts.app')

@section('content')
<div class="container">

            ーー省略ーー

            @if(isset($article))
            <div class="text-center">
                <button type="button" class="btn btn-secondary" onClick="history.back()">戻る</button>

                ーーここから追加ーー
                <form style="display:inline" action="{{ route('articles.destroy', $article->id) }}" method="post">
                    @method('DELETE')
                    @csrf
                    <button type="submit" class="btn btn-danger ml-3">
                        {{ __('削除') }}
                    </button>
                </form>
                ーーここまで追加ーー

                <button type="button" class="btn btn-primary ml-3" onClick="location.href='{{ route('articles.edit', $article->id) }}'">
                    編集
                </button>
            </div>
            @endif

            ーー省略ーー

</div>
@endsection
```

### 2. 削除処理実装

```php:ArticleController.php
// destroyメソッドの部分のみ抜粋
public function destroy(Int $id)
{
    // 選択された記事データを取得
    $article = Article::find($id);

    // 削除処理実行
    $article->delete();

    // 記事一覧画面へ
    return redirect()->route('articles.index');
}
```
削除したい記事のデータを取得して、`$article->delete()`でデータを削除しています。


## ルーティングの見直し
現在は`http://127.0.0.1:8000/articles`とアクセスすると記事一覧画面が表示されますが、`http://127.0.0.1:8000`と検索しただけで記事一覧画面を表示して行こうと思います。

`routes/web.php`を編集していきます。

```php:web.php
<?php

Route::get('/', 'ArticleController@index')->name('articles.index'); // ここを追記

Route::resource('articles', 'ArticleController')->except('index'); // ここを編集

Auth::routes(); // bootstrap導入時に勝手に追記されている

Route::get('/home', 'HomeController@index')->name('home'); // bootstrap導入時に勝手に追記されている
```
except('メソッド名')とすると、指定したメソッドはルーティングされなくなります。
その代わりに`Route::get('/', 'ArticleController@index')->name('articles.index');`としてあげることで、`http://127.0.0.1:8000`にアクセスしただけで記事一覧画面が表示されるようになりました。
`$ php artisan route:list`をしてみてもexceptする前と同じだと思います。
ぜひ確かめてみてください。

# 最後に
これでCRUD機能の実装は終了です。
これからは、これを元に色々やっていきたいと思います。

少しでも役に立った！という時は、いいねをポチッとして
フォローしてくださると嬉しいです、、、笑

役に立たなかった時は、怒らないでコメント頂けますと幸いです笑

Twitterもやってますので、よかったら見てみてくださいね！
https://twitter.com/jefftechsaku