2019-11-11に投稿

受け取った質問一覧ページを作る

次は受け取った質問の一覧ページを作成します。一通り主要な詳細ページは作ってきましたが、今のままではサービスとしては利用できません。受け取った質問一覧ページを作成し、全ての質問にアクセスできるようにします。

質問一覧ページを作成

実際に質問一覧ページを作成していきます。

アクションを作成

まずは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コンポーネントが良さそうですのでこれを利用します。

Badges · Bootstrap

下記のように調整しました。

  @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です。

SQLの実行を最適化する

しかし一つ問題点として、ループの中で$question->answerを実行しているため、ループの中で何回もSQLのデータ処理が行われてしまいます。データが20件あれば最初の一覧取得と毎回の回答取得で21回も呼ばれてしまうため負荷的には非効率です。

そのため、LaravelのEagerローディングを利用します。

Eagerロード

これだと最初に質問一覧を取った時、その質問のIDに紐づく回答を全て取得して紐付けておいてくれるため、今回の場合だと合計2回のクエリ実行で済みます。アクションのデータ取得部分を下記のように調整します。

        $questions = Question::with('answer')
            ->where('received_user_id', Auth::id())
            ->orderByDesc('id')
            ->paginate();

withをつけることでEagerローディングが行われるようになります。

次は

あとは未回答のものだけを絞り込む機能をつけようかと思いましたが、せっかくLaravel Mixを使っているのでVue.jsのコンポーネントを使った簡単なJavaScriptの処理を入れて実装してみたいと思いますので次回に分けることにします。


view_list [連載] Laravelで質問箱みたいなサービスを作る
第3回 質問できるようにする
第4回 Bootstrapでベースデザインを整える
第5回 質問に回答する機能を作る
第6回 Twitterシェア用のOGPを作成する
第7回 受け取った質問一覧ページを作る

だら@Crieit開発者

Crieitの開発者です。 主にLAMPで開発しているWebエンジニアです(在宅)。大体10年程。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel5, CakePHP3, JavaScript, RoR 趣味:Elixir, Phoenix, Node, Nuxt, Express, Vue等色々

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント