非同期通信での正誤判定機能の実装~ChatGPTと一緒に一問一答アプリを開発した話②~

eyecatch-wchatgpt-2

「一問一答アプリ × ChatGPT」

先日、ChatGPTを活用して一問一答アプリケーション「情報1 一問一答トレーニングGYM」を開発したことをお伝えしました。

▶︎こちらの記事で紹介しています。

iqatlogo2【ChatGPTと開発】高校「情報1」一問一答アプリ

私が開発したこのアプリは、ChatGPTの力を借りながら、実装していきました。

この記事では、一問一答アプリ × ChatGPTの開発の舞台裏や、実際の活用方法について詳しく解説します。

今回は

  • 非同期通信での正誤判定機能

という機能を実装するにあたって、どのように役立ったのか、その様子を紹介します!

ぜひこのシリーズの記事をチェックして、一問一答アプリの新たな魅力とChatGPTとの相乗効果を体感してください!

非同期通信での正誤判定機能の実装

img-4372v2

参考にしているwebアプリケーションはページ遷移せずに正誤判定を行ってくれるので、同じような機能を実装したい!ということで、非同期通信で正誤判定ができないか実装してみました。

前回までの開発では問題が表示されるアクションと正誤判定する機能を別のアクションに切り分け、ページ遷移して正誤判定するという流れをとっていました。

コトゼニ
コトゼニ

Ajaxを利用して実現させていきたいと思います。

ActionController::InvalidauthenticityTokenが出てサーバーへ送信できない

programming

実装の詳細な途中経過は割愛しますが、取得した選択肢のid(choice_id)をサーバーへ送ろうとすると

statusコード422が表示され、リクエストがサーバーに届いていないことが判明しました。

調べてみるとターミナルで以下のように表示されています。

ターミナル画面

一番上のActionController::InvalidauthenticityTokenの部分をchatGPTに相談してみたら、

chatGPTとの対話履歴3トークン

とわかりやすく説明してくれて、解決するコードまで教えてくれました。

この現象はクロスサイト攻撃に対するセキュリティがrailsではデフォルトで備わっているから。

なので、操作するbutton_toタグからでもトークンを取得できるように変更しました。

コトゼニ
コトゼニ

chatGPTから教えてもらったのは以下のコードを追記するとこの問題を解決できるとのこと

xhr.setRequestHeader('X-CSRF-Token', token); // トークンをリクエストヘッダーに追加

実装後のソースコード

cyber

実装した結果のソースコードがこちらです。

check_answer.js

function check_answer(){
  const buttons = document.querySelectorAll(".buttons");

	buttons.forEach(function(button){
    button.addEventListener("click",function(e){
      e.preventDefault();
      var token = document.getElementsByName('csrf-token')[0].content;
      var choice_id = this.getAttribute('data-choice-id');

      const xhr = new XMLHttpRequest();
      xhr.open('POST', '/questions/check', true);
      xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
      xhr.setRequestHeader('X-CSRF-Token', token); // トークンをリクエストヘッダーに追加
      xhr.onload = function() {
        if (xhr.status === 200) {
          // 正誤判定の結果を表示
          var data = JSON.parse(xhr.responseText);
          var result = data.result ? '正解!' : '不正解...';
          document.querySelector('#result').textContent = result;
        }
        else {
          console.error(xhr.statusText);
        }
      };

      xhr.send('choice_id=' + encodeURIComponent(choice_id));

    });
  });
};


window.addEventListener('load',check_answer);

コントローラーはこちら

questions_controller.rb

 def check
    # binding.pry
    # 選択された値の正誤を判定
    choice = Choice.find(params[:choice_id])
    if choice.is_answer == 1
      result = true
    else
      result = false
    end
    # 正誤判定の結果をJSON形式で返す
    render json: { result: result }
  end

ビューファイルも(現時点で)こんな感じ


<div class="contents row">
  <div class="question_id">
    <%= "問題 #{@question.id}"%>
  </div>
  <div class="sentense">
  <p>次の問題文の答えとして最も適している語句を選びなさい。</p>
  </div>
  <div class="question_text">
    <%= @question.text%>
  </div>
  <div class="choices">
      <h4><解答一覧></h4>
      <p>ア.  <%= @choices[0].choice%></p>
      <p>イ.  <%= @choices[1].choice%></p>
      <p>ウ.  <%= @choices[2].choice%></p>
      <p>エ.  <%= @choices[3].choice%></p>
    
    <div class="button-list" style="display:flex;" id="button-list">
    <%= button_to "ア", "/questions/result", {method: :post, params: {choice_id: @choices[0].id, question_id: @question.id}, class: "buttons",data: { "choice-id" => @choices[0].id, "choice-name" =>"ア", "question-id" => @question.id},"csrf-token" => form_authenticity_token  }%>
    <%= button_to "イ", "/questions/result", {method: :post, params: {choice_id: @choices[1].id, question_id: @question.id}, class: "buttons",data: { "choice-id" => @choices[1].id, "choice-name" =>"イ", "question-id" => @question.id},"csrf-token" => form_authenticity_token  }%>
    <%= button_to "ウ", "/questions/result", {method: :post, params: {choice_id: @choices[2].id, question_id: @question.id}, class: "buttons",data: { "choice-id" => @choices[2].id, "choice-name" =>"ウ", "question-id" => @question.id},"csrf-token" => form_authenticity_token  }%>
    <%= button_to "エ", "/questions/result", {method: :post, params: {choice_id: @choices[3].id, question_id: @question.id}, class: "buttons",data: { "choice-id" => @choices[3].id, "choice-name" =>"エ", "question-id'" => @question.id},"csrf-token" => form_authenticity_token  }%>
    </div>

  <%= button_to "解答を見る", "/questions/result", {method: :post, params: {choice_id: 0, question_id: @question.id}, id: "seeAnsButton", class: "buttons",data: { "choice-id" => 0,"choice-name" =>"-" , "question-id'" => @question.id},"csrf-token" => form_authenticity_token  }%>

  <div id="result"></div>

  <p>------</p>
  <p><%= link_to '問題選択へ戻る', root_path, method: :get %>

</div>

そして実装後の挙動はこんな感じです。

Ajaxで正誤判定
コトゼニ
コトゼニ

これでページ遷移せずに正誤判定機能を実装できました

chatGPTとのやりとり【余談】

ちなみに情報ではあるのですが、下地作りのためにも、Ajaxで正誤判定を実現するためにchatGPTにもコード作成を依頼してみました。その結果が以下です。

コトゼニ
コトゼニ

以下の要件を満たすコードをrailsで作成してください。必要に応じてjavascriptを使用してもかまいません▼要件・選択された回答に含まれた値(この値を仮にchoice_idとする)をparamsとして送信する・その値を用いてAjaxでサーバーと接続し正誤判定する。・正誤判定の結果はjavascriptで表示する

chatGPT
chatGPT

以下は、要件を満たす可能性があるコード例です。詳細な実装については、環境や要件によって異なるため、必要に応じて変更してください。

HTML側

<!-- 回答のラジオボタンを作成 -->
<% @question.choices.each do |choice| %>
  <div>
    <%= radio_button_tag 'choice_id', choice.id, false %>
    <%= label_tag "choice_#{choice.id}", choice.content %>
  </div>
<% end %>

<!-- 「回答する」ボタンを作成 -->
<button id="submit-btn">回答する</button>

<!-- 回答の正誤を表示する要素を作成 -->
<div id="result"></div>
JavaScript側

// 「回答する」ボタンをクリックしたときの処理
$('#submit-btn').on('click', function() {
  // 選択された値を取得
  var choice_id = $('input[name="choice_id"]:checked').val();

  // Ajaxで正誤判定を実行
  $.ajax({
    type: 'POST',
    url: '/questions/check',
    data: { choice_id: choice_id },
    dataType: 'json'
  }).done(function(data) {
    // 正誤判定の結果を表示
    var result = data.result ? '正解!' : '不正解...';
    $('#result').text(result);
  });
});

Rails側

rubyCopy code
# config/routes.rbにルーティングを追加
post '/questions/check', to: 'questions#check'

# app/controllers/questions_controller.rb
class QuestionsController < ApplicationController
  def check
    # 選択された値の正誤を判定
    choice = Choice.find(params[:choice_id])
    result = choice.correct?

    # 正誤判定の結果をJSON形式で返す
    render json: { result: result }
  end
end

chatGPTが提示してくれたコードも非常に参考になりました!

まとめ

今回の開発作業で

  • 非同期通信での正誤判定機能

を実装することができました。

ChatGPTを利用すると開発がグンと楽になりますね!ChatGPTの可能性を体験してみてはいかがでしょうか?

最後まで読んでいただきありがとうございました。

この記事が少しでも参考になれば幸いです。

それではまたここで会いましょう!

ブログランキング・にほんブログ村へにほんブログ村

ブログ村に参加中です。上のバナーをクリックいただくだけで当ブログにポイントが入ります。いつも応援クリックありがとうございます。

Twitter

Twitter やってます。

新着記事のお知らせをしていますのでぜひフォローしてください!

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA