2021/11/12 変更点
① modelの設定(fillable)
$fillable に 「’user_id’」を追加しました。
② データベースに保存できるようにする。
(新)を作成しました。こちらを参照ください。
Contents
Post投稿画面を作成する
新規投稿ページを作成する
投稿一覧画面に新規追加ボタンを記入しましょう。
index.blade.php
//index.blade.php @extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card text-center"> <div class="card-header"> 投稿一覧 </div> <div class="card-body"> <h5 class="card-title">1回目の投稿</h5> <p class="card-text">油そばは春日亭も好きですが、kirinjiが一番好きです</p> <a href="#" class="btn btn-primary">詳細へ</a> </div> <div class="card-footer text-muted"> 2日前 </div> </div> </div> <div class="col-md-2">//追加 <a href="{{ route('posts.create') }}" class="btn btn-primary">新規投稿</a> </div> </div> </div> @endsection
新規投稿のaタグのリンク先を「posts.create」にしました。
試しにボタンを押すと、

/posts/create に飛べましたね。
次に
PostController.phpをひらきましょう。
新規投稿画面を作成するので、「public function create」に書き込んでいきます。
public function create() { return view('posts.create'); →追加(postsディレクトリのcreate.blade.phpという意味) }
同時にcreate.blade.phpも編集していきましょう。Bootstrapのformを改造して使います。
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <form action="{{ route('posts.store') }}" method="POST"> {{csrf_field()}} <div class="form-group"> <label>タイトル</label> <input type="text" class="form-control" placeholder="タイトルを入力して下さい" name="title"> </div> <div class="form-group"> <label>内容</label> <textarea class="form-control" placeholder="内容" rows="5" name="body"></textarea> </div> <button type="submit" class="btn btn-primary">作成する</button> </form> </div> </div> </div> @endsection
formタグのアクション先を「posts.store」にし、methodはPOST!!!
csrf_fieldを忘れずに記入しましょう!!(csrf保護については下の記事を流し見することをお勧めします。)
バリデーションを行う
保存したい内容を入力し、「作成するボタン」を押すことで PostControllerのstoreメソッドまで送ることができるようになりました。
確認をしてみましょう。ここで使うのはdd()というデバックです。
public function store(Request $request) { dd($request); →追加 }
このメソッドでは「$request」を受け取っています。この中には、「create.blade」で入力した値が入っているはずなので、ddで中身を確認してみましょう。

作成ボタンを押すと。

ちゃんと入ってきていますね。
次にやることはバリデーションです。
「バリデーション」では入力された内容をチェックして妥当性があるかを確認する作業です。
例えば、blogのタイトルは3文字以上がいいよね….とかです。
//bash % php artisan make:request PostRequest
すると、Http Request 配下にPost.phpが作成されるます。
こちらにいろいろなルール付をすることができます。
//Post.php public function authorize() { return true; →trueに変更 } public function rules() { return [ 'title' => 'required|max:20', 'body' => 'required', ]; } public function messages() { return [ 'title.required' => 'タイトルは必須です。', 'title.max' => 'タイトルは20文字以内で記入してください。', 'body.required' => '内容は必須です。', ]; }
次にこの作成したルールを適用させます。
PostController.phpを開きましょう。
namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Http\Requests\PostRequest; →追加 public function store(PostRequest $request) →PostRequestを適用 { dd($request); }
そして先ほど設定したバリデーションメッセージを表示できるように記載しましょう。
create.blade.php
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> @if ($errors->any()) //追加 <div class="alert alert-danger"> <ul> @foreach ($errors->all() as $error) <li>{{ $error }}</li> @endforeach </ul> </div> @endif <form action="{{ route('posts.store') }}" method="POST"> {{csrf_field()}} <div class="form-group"> <label>タイトル</label> <input type="text" class="form-control" placeholder="タイトルを入力して下さい" name="title"> </div> <div class="form-group"> <label>内容</label> <textarea class="form-control" placeholder="内容" rows="5" name="body"></textarea> </div> <button type="submit" class="btn btn-primary">作成する</button> </form> </div> </div> </div> @endsection
エラーが返ってきて表示ができるようになりました!確認してみましょう。

タイトル、内容を入れずに作成するボタンを入力すると、エラーが出るようになりました!!
下のドキュメントに目を通しましょう。
modelの設定(fillable)
modelにfillableを設定しましょう。
app 配下 Post.php
class Post extends Model { protected $fillable = ['title', 'body', 'user_id']; }
app 配下 Comment.php
class Comment extends Model { protected $fillable = ['body']; }
のように変更しましょう。
$fillableに設定したもの以外のカラムはユーザーが変更できないようにできます。
例えば、IDや今回は作成しませんがadminなどの情報を、ユーザーに変更されてしまうとサイトの脆弱性につながります。それらを回避するために、モデルにユーザーの入力によって変更できるカラムを指定します。
(新)データベースに保存できるようにする。
入力した内容をチェックすることができるようになりましたので、次はデータベースに保存できるようにしていきます。
PostController.php
use Illuminate\Http\Request; use App\Http\Requests\PostRequest; use App\Post; use Auth; class PostController extends Controller { public function __construct() { $this->middleware('auth'); } --省略--- public function store(PostRequest $request) { $input = $request->all(); // ユーザーが入力した $request の配列を $input に代入します。 $input['user_id'] = Auth::id(); // user_id は Auth::id() で取得し $input の配列に追加します。 Post::create($input); // create() を使用して新規投稿を保存しましょう。 return redirect()->route('posts.index'); }
$input にユーザーからの入力を代入しています。
Post には、title body user_id を保存しますが、「user_id」はユーザーからの入力では得ることができないので Auth::id() で取得、$input の配列に追加しましょう。
create メソッドを使用すると、$fillable で指定したカラムを保存することができます。
一行で保存処理が実行できるので便利ですね。
https://readouble.com/laravel/6.x/ja/eloquent.html
(旧)データベースに保存できるようにする。
入力した内容をチェックすることができるようになりましたので、次はデータベースに保存できるようにしていきます。
PostController.php
use Illuminate\Http\Request; use App\Http\Requests\PostRequest; use App\Post; use Auth; class PostController extends Controller { public function __construct() { $this->middleware('auth'); } --省略--- public function store(PostRequest $request) { ***$post = new Post; //インスタンスを作成 $post -> title = $request -> title; //ユーザー入力のtitleを代入 $post -> body = $request -> body; //ユーザー入力のbodyを代入 $post -> user_id = Auth::id(); //ログイン中のユーザーidを代入 $post -> save(); //保存してあげましょう return redirect()->route('posts.index'); }
ここでは「use」するものを2つ増やし、「function」を1つ追加、「store function」の中身を追加しました。
- use App\Postと use Auth
- use AppはこのcontrollerでPostモデルを使うよという意味。
- use Authは
- function __construct()ではミドルウェアをこのコントローラーに付与しています。 ログインしていないユーザーはこのコントローラーのメソッドを1つも動かせなくなりました🙌 ログインしていない状態で、「/posts」にアクセスするとログイン画面に飛ばされます。
- store について詳しくみていきます。 ユーザーの入力値($request)、ログイン中のユーザーIDを代入し保存している。
DBから一覧ページに表示する。
一覧ページはまだ固定の投稿しか表示できていません。
今回はDBから引っ張ってきた投稿を一覧で表示できるようにしましょう。
まずはコントローラーでデータベースからデータを取得しましょう。
PostController.php
public function index() { $posts = Post::all(); return view('posts.index', compact('posts')); //return view('posts.index'); }
ここでは、Postモデルを通し、postsテーブルからデータを全取得(all)。$postsという変数に代入しました。
compact関数というものを用いて、$postsをpostsのindexに渡しています。
index.php にて
@extends('layouts.app') @section('content') <div class="container"> <div class="row justify-content-center"> <div class="col-md-8"> <div class="card text-center"> <div class="card-header"> 投稿一覧 </div> @foreach ($posts as $post) <div class="card-body"> <h5 class="card-title">タイトル:{{ $post->title }}</h5> <p class="card-text">***内容:{{ $post->body }}</p> <a href="#" class="btn btn-primary">詳細へ</a> </div> <div class="card-footer text-muted"> 投稿日時:{{ $post->created_at }} </div> @endforeach </div> </div> <div class="col-md-2"> <a href="{{ route('posts.create') }}" class="btn btn-primary">新規投稿</a> </div> </div> </div> @endsection
解説。$postsを1つずつforeachで回すことで、全件の内容を表示する。
@foreach ($posts as $post) → $postsの中身を$postとして回す。 <h5 class="card-title">タイトル:{{ $post->title }}</h5> <p class="card-text">内容:{{ $post->body }}</p> @endforeach
ここで一覧ページをみてみましょう。

一欄ページに全てのpostを表示することができるようになりました。
今回はここまで!お疲れ様でした。
titleとbodyを入力してボタンを押すと
Column not found: 1054 Unknown column ‘updated_at’ in ‘field list’ (SQL: insert into `posts` (`title`, `body`, `user_id`, `updated_at`, `created_at`) values (test1, content1, 1, 2021-12-28 17:56:08, 2021-12-28 17:56:08))
というエラーが出てしまいます
MySQL側のミスでしょうか?
コードにミスがあるのでしょうか?
検索して色々やってみたら解消されました!
引き続き勉強させていただきます