次は受け取った質問の一覧ページを作成します。一通り主要な詳細ページは作ってきましたが、今のままではサービスとしては利用できません。受け取った質問一覧ページを作成し、全ての質問にアクセスできるようにします。
実際に質問一覧ページを作成していきます。
まずはQuestionControllerに一覧ページ用のアクションを追加します。getではなくpaginateを使うことでページ切り替えをして全て閲覧できるようにしています。
public function index()
{
$questions = Question::where('received_user_id', Auth::id())
->orderByDesc('id')
->paginate();
return view('question.index', compact('questions'));
}
このアクション用のルーティングを設定します。authミドルウェアが設定されているQuestionControllerの設定にindexを追加します。元々storeのルーティングが作成済みだったのでそちらに追記します。
Route::resource('questions', 'QuestionController')->only(['index', 'store']);
次にresources/views/question/index.blade.php
を作成します。
@extends('layouts.app')
@section('content')
<section class="text-center">
<h1 style="font-size: 1.5rem">届いた質問一覧</h1>
@foreach ($questions as $question)
<a href="{{ url("questions/{$question->id}/received") }}">
<div class="card mb-4">
<div class="card-body">
{{ $question->body }}
</div>
</div>
</a>
@endforeach
<div class="text-center d-inline-block">
{{ $questions->links() }}
</div>
</section>
@endsection
これでログインした状態でhttp://localhost:8000/questions
にアクセスすれば表示されます。
これでアクションのpaginate()
をpaginate(2)
等にして1ページ内のデータ表示数を試しに変えてみることでページの表示も確認できます。
このままだと回答したかどうかが分かりづらいため、未回答かどうかも表示するようにしてみます。
Questionは一つのAnswerを持っているため、そのデータがあるかどうかで判断ができます。これは$question->answer
のようにして取得できます。テンプレートを調整していきますが、回答済、未回答を表示するのはBootstrapの下記のbadgeコンポーネントが良さそうですのでこれを利用します。
下記のように調整しました。
@foreach ($questions as $question)
<a href="{{ url("questions/{$question->id}/received") }}">
<div class="card mb-4">
<div class="card-body">
{{ $question->body }}
@if ($question->answer)
<span class="badge badge-success">回答済</span>
@else
<span class="badge badge-warning">未回答</span>
@endif
</div>
</div>
</a>
@endforeach
表示状はもうこれでOKです。
しかし一つ問題点として、ループの中で$question->answer
を実行しているため、ループの中で何回もSQLのデータ処理が行われてしまいます。データが20件あれば最初の一覧取得と毎回の回答取得で21回も呼ばれてしまうため負荷的には非効率です。
そのため、LaravelのEagerローディングを利用します。
これだと最初に質問一覧を取った時、その質問のIDに紐づく回答を全て取得して紐付けておいてくれるため、今回の場合だと合計2回のクエリ実行で済みます。アクションのデータ取得部分を下記のように調整します。
$questions = Question::with('answer')
->where('received_user_id', Auth::id())
->orderByDesc('id')
->paginate();
withをつけることでEagerローディングが行われるようになります。
あとは未回答のものだけを絞り込む機能をつけようかと思いましたが、せっかくLaravel Mixを使っているのでVue.jsのコンポーネントを使った簡単なJavaScriptの処理を入れて実装してみたいと思いますので次回に分けることにします…と思いましたがそこまで必要性を感じられていないのでとりあえず普通にJavaScript無しで実装していきます。
第5回 | 質問に回答する機能を作る |
第6回 | Twitterシェア用のOGPを作成する |
第7回 | 受け取った質問一覧ページを作る |
第8回 | LaravelのDebugbarを導入する |
第9回 | 未回答のものを絞り込む機能を追加する |
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント