Help us understand the problem. What is going on with this article?

Railsで基本情報技術者試験の過去問題サイトを作る(8:自動解答編)

More than 1 year has passed since last update.

はじめに

ゆる〜く学ぶ。みんなのWeb勉強コミュニティー。 「にゅ〜ぶる会」を運用中です。
https://newburu.github.io/

そこで、何か教育用のコンテンツが欲しいなぁ〜と思い立ち、今回の企画をスタートしました!

Railsで基本情報技術者試験の過去問題サイトを作ります!

最終目標

  • 問題・解答の登録は、Scaffoldで簡易でOK
  • APIを用意して、ランダムに問題を抽出する機能を追加する
  • TwitterBOT、LINEBOT、SlackBOTが出来たら良いな

履歴

1:構築編
  https://qiita.com/newburu/items/ed59f47ac645b19620f6
2:日本語化(i18n)編
  https://qiita.com/newburu/items/4f12fdb61bf6cd601545
3:親子関係、登録編
  https://qiita.com/newburu/items/f2a20289be5ec1fc1b77
4:親子関係、参照編
  https://qiita.com/newburu/items/51b11bd02691efc2cc0d
5:API編
  https://qiita.com/newburu/items/89f9f847a2648bdd006c
6:SlackBOT編
  https://qiita.com/newburu/items/aeeb9acb453da786bd59
7:Herokuデプロイ〜自動化編
  https://qiita.com/newburu/items/0a8bb02e1e8c8fe737c7
8:自動解答編
  本ページ

今回やる事

  • Slackに投稿した問題に、スレッドで解答を投稿する。

Slackのスレッドで投稿します。

1. SlackAPIでのスレッド投稿について理解しましょう。

※参考
 https://api.slack.com/methods/chat.postMessage

  • Slack.chat_postMessageのレスポンスで、tsが返って来ます。
    ※これが、その投稿の識別IDになるようです。
  • 投稿時(Slack.chat_postMessage)のオプション「thread_ts」に、先ほどのtsを指定すると、スレッドとして投稿されるようです。

2. 投稿した履歴を記憶するモデルに追加します。

名前 物理名 備考
問題ID question_id 数値(integer)
投稿したSlackTS slack_ts 文字列(string)
ステータス status 数値(integer) Enum使う

Modelを作成します。

Scaffold
例) rails g[enerate] model モデル名 カラム名1:データ型1 カラム名2:データ型2 …
$ rails g model History question:references slack_ts:string status:integer
DB作成
$ rake db:migrate

ステータス(status)にEnumの設定を行います。

models/History.rb
class History < ApplicationRecord
  belongs_to :question

  enum status: {do: 0, done: 1}
end

3. 投稿時に履歴を保存します。

投稿時のタスクに、履歴を保存するロジックを追加します。

lib/tasks/slack_bot.rake
namespace :slack_bot do
  desc 'ランダムに問題をSlackに書き込む'
  task :random_question => :environment do
  
  〜 中略 〜

    # text:出力テキスト、channel:出力先のチャンネル名、username:表示ユーザ名
    ret = Slack.chat_postMessage(text: msg, channel: ENV["SLACK_CHANNEL_NAME"], username: ENV["SLACK_BOT_NAME"])

    History.create(question: question, slack_ts: ret['ts'], status: :do)
  end
end

4. 手動で動かして問題ないか確認しましょう。

手動実行
rake slack_bot:random_question

Historiesテーブルにレコードが追加されればOKです!

5. 解答の投稿タスクを追加しましょう。

lib/tasks/slack_bot.rake
namespace :slack_bot do
  desc '解答をSlackに書き込む'
  task :answer => :environment do
    # 未解答の履歴一覧を取得
    History.where(status: :do).each do |history|
      question = history.question
      answers = question.answers.where(correct: true)

      # 解答テキスト
      # HACK:ちょっと無理やり感があるので、リファクタ候補
      answer_msg = []
      first_answer = question.answers.order(:id).first
      answers.each do |a|
        answer_msg << "#{%w(   )[a.id - first_answer.id]}"
      end
      msg = "【解答】" + answer_msg.join("、")

      # thread_ts:投稿先スレッドTS、text:出力テキスト、channel:出力先のチャンネル名、username:表示ユーザ名
      Slack.chat_postMessage(thread_ts: history.slack_ts, text: msg, channel: ENV["SLACK_CHANNEL_NAME"], username: ENV["SLACK_BOT_NAME"])

      # 解答済みに変更
      history.update(status: :done)
    end
  end
end

6. 確認しましょう

まずは、rakeタスクとして登録されているか確認しましょう。

$ rake -vT

〜 略 〜
rake slack_bot:answer                   # 解答をSlackに書き込む
〜 略 〜

では、実行!

$ rake slack_bot:answer

Slackを確認し、こんな感じの表示されればOKです!

Slackを確認

7. Herokuにデプロイし、Heroku Schedulerの設定をしましょう。

設定方法については、省略させて頂きますね。

注意点としては、「問題タスク」の後に「解答タスク」を動かすと、即解答してしまうので、
「解答タスク」を実行した後に、「問題タスク」を実行するように設定してください。
※これで、次のタスク実行時に、前回タスクで書き込まれた問題に解答が書き込まれるようになります。

今回はここまで

ありがとうございました!
次回は、またいつになるかわかりませんが…💦
基本情報の問題には、表が含まれる場合がありますので、問題に画像を登録出来るようにしたいと思います。

newburu
座右の銘は「晴笑雨笑」🔸駆け出しエンジニアさんの力になりたい。無料で楽しく!勉強/質問コミュニティを運用中(http://newburu.github.io)🔸自分のペースでゆっくりでも勉強したい方、ご連絡ください。ご協力します!
https://newburu.com
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away