Railsで基本情報技術者試験の過去問題サイトを作る（８：自動解答編）

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

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

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

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

# 履歴
１：構築編
　　https://qiita.com/newburu/items/ed59f47ac645b19620f6
２：日本語化(i18n)編
　　https://qiita.com/newburu/items/4f12fdb61bf6cd601545
３：親子関係、登録編
　　https://qiita.com/newburu/items/f2a20289be5ec1fc1b77
４：親子関係、参照編
　　https://qiita.com/newburu/items/51b11bd02691efc2cc0d
５：API編
　　https://qiita.com/newburu/items/89f9f847a2648bdd006c
６：SlackBOT編
　　https://qiita.com/newburu/items/aeeb9acb453da786bd59
７：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を作成します。

```terminal:Scaffold
例） rails g[enerate] model モデル名 カラム名1:データ型1 カラム名2:データ型2 …
$ rails g model History question:references slack_ts:string status:integer
```

```terminal:DB作成
$ rake db:migrate
```

### ステータス(status)にEnumの設定を行います。
```ruby:models/History.rb
class History < ApplicationRecord
  belongs_to :question

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

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

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

```ruby: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. 手動で動かして問題ないか確認しましょう。

```terminal:手動実行
rake slack_bot:random_question
```
Historiesテーブルにレコードが追加されればOKです！

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

```ruby: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です！

<img width="431" alt="Slackを確認" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/118481/1db68177-3285-a07a-5471-b11da81e8f18.png">

## 7. Herokuにデプロイし、Heroku Schedulerの設定をしましょう。
設定方法については、省略させて頂きますね。

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

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