rails クイズアプリ作ってみた

# やること
- 問題数合計50問程度からランダムで10問を選び出題する
- ユーザーのログインなしで回答できる
- 回答は全クイズにおいて4択の選択式
- 回答後に正答率を表示

# 完成イメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/58d45ce2-e5b8-d150-ffd8-48bdd1632565.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2586059/f27661a4-825f-ba38-c4ef-598ee5387f55.png)

# データベース構成
テーブル名: questions
- content (質問の内容を格納する文字列)
- option1, option2, option3, option4 (選択肢の文字列)
- correct (正解の選択肢を表す整数)

テーブル名: user_answers
- q1_id から q10_id (質問のID)
- q1_yourans から q10_yourans (ユーザーの回答を表す整数)
- q1_isCorrect から q10_isCorrect (ユーザーの回答が正解かどうかを表す真偽値)


# 作っていく！
### モデル作成
```bash:コマンドプロンプト
rails g model Question
rails g model User_answer
```

```diff_ruby:/db/migrate/~~_create_quesitons.rb
class CreateQuesitons < ActiveRecord::Migration[6.1]
  def change
    create_table :questions do |t|
+      t.string :content
+      t.string :option1
+      t.string :option2
+      t.string :option3
+      t.string :option4
+      t.integer :correct

      t.timestamps
    end
  end
end
```
```diff_ruby:/db/migrate/~~_create_user_answers.rb
class CreateUserAnswers < ActiveRecord::Migration[6.1]
  def change
    create_table :user_answers do |t|
+      t.integer :q1_id
+      t.integer :q2_id
+      t.integer :q3_id
+      t.integer :q4_id
+      t.integer :q5_id
+      t.integer :q6_id
+      t.integer :q7_id
+      t.integer :q8_id
+      t.integer :q9_id
+      t.integer :q10_id
+
+      t.integer :q1_yourans
+      t.integer :q2_yourans
+      t.integer :q3_yourans
+      t.integer :q4_yourans
+      t.integer :q5_yourans
+      t.integer :q6_yourans
+      t.integer :q7_yourans
+      t.integer :q8_yourans
+      t.integer :q9_yourans
+      t.integer :q10_yourans
+
+      t.boolean :q1_isCorrect
+      t.boolean :q2_isCorrect
+      t.boolean :q3_isCorrect
+      t.boolean :q4_isCorrect
+      t.boolean :q5_isCorrect
+      t.boolean :q6_isCorrect
+      t.boolean :q7_isCorrect
+      t.boolean :q8_isCorrect
+      t.boolean :q9_isCorrect
+      t.boolean :q10_isCorrect

      t.timestamps
    end
  end
end
```
```bash:コマンドプロンプト
rails db:migrate
```
seedを使って問題を登録します
(中身はてきとーです、自分の好きな問題にしておいてください)
```ruby:db/seeds.rb
50.times do |i|
  Question.create(
    content: "テスト用#{i}の問題だよ！",
    option1: "テスト用#{i}の選択肢1だよ",
    option2: "テスト用#{i}の選択肢2だよ",
    option3: "テスト用#{i}の選択肢3だよ",
    option4: "テスト用#{i}の選択肢4だよ",
    correct: i % 4 + 1,
  )
end
```
```bash:コマンドプロンプト
rails db:seed
```

### コントローラ作成
##### tops編

```bash:コマンドプロンプト
rails g controller tops
```
```ruby:app/controllers/tops_controller.rb
class TopsController < ApplicationController
  def index
  end
end
```
`index.html.erbを作成`
```erb:views/tops/index.html.erb
<h1>Top Page</h1>

<%= link_to  "10問クイズに挑戦", quiz_path(1) %>
```

##### quizzes編
こっからがちょっとえぐめです

```bash:コマンドプロンプト
rails g controller quizzes
```
```ruby:app/controllers/quizzes_controller.rb
class QuizzesController < ApplicationController
  def show
    @q_num = params[:id]
    if @q_num != '1'
      @user_id = params[:user_id]
    end
    q_sum = Question.count
    rand_num = SecureRandom.random_number(q_sum) + 1
    @q = Question.find(rand_num)
  end

  def create
    q_num = params[:q_num].to_i
    user_id = params[:user_id].presence
    user_ans = user_id ? UserAnswer.find(user_id) : UserAnswer.new

    q_attr = "q#{q_num}_"
    user_ans[q_attr + 'id'] = params[:q_id].to_i
    user_ans[q_attr + 'yourans'] = params[:choice].to_i
    user_ans[q_attr + 'isCorrect'] = (Question.find(params[:q_id].to_i).correct == params[:choice].to_i)
    user_ans.save

    redirect_to q_num == 10 ? result_path(user_id: user_ans.id) : quiz_path(q_num + 1, user_id: user_ans.id)
  end

  def result
    @user_ans = UserAnswer.find(params[:user_id])
  end
end
```
showアクションではクイズの問題をランダムで選出しています
`@q_num`は第oo問にあたり、`@q`がランダムに選出した問題になります
しかし、ここでは10問選ばれるうちに同じ問題が選ばれてしまう可能性があるので、のちに出てくる`UserAnswer`を参照して1度選ばれた問題は選ばれないようにした方がいいかもしれません
（具体的な実装方法はこの記事では記載しておりません）
createアクションでは1問ごとにその結果をUserAnswerに記録していってます
複雑になってしまっているのは第1問の時は、新しくUserAnswerにレコードを追加し、第2問以降は第1問で作成したレコードをupdateする形にしているからです〜〜
ややこしいですwww

```erb:views/quizzes/show.html.erb
<h1>第<%= @q_num %>問  <%= @q.content %></h1>

<%= form_with(url: quizzes_path, method: :post) do |f| %>
  <%= f.label :選択肢 %><br>
  <%= f.radio_button :choice, 1 %> <%= @q.option1 %> <br>
  <%= f.radio_button :choice, 2 %> <%= @q.option2 %> <br>
  <%= f.radio_button :choice, 3 %> <%= @q.option3 %> <br>
  <%= f.radio_button :choice, 4 %> <%= @q.option4 %> <br>

  <%= f.hidden_field :q_id, :value => @q.id %>
  <%= f.hidden_field :q_num, :value => @q_num %>
  <% if @q_num != '1' %>
    <%= f.hidden_field :user_id, :value => @user_id %>
  <% end %>

  <% if @q_num.to_i < 10 %>
    <%= f.submit '次の問題へ' %>
  <% else %>
    <%= f.submit '結果を表示する' %>
  <% end %>

<% end %>
```
```erb:views/quizzes/result.html.erb
<h1>結果表示ページ</h1>

<% (1..10).each do |i| %>
  <% q_attr = "q#{i}_" %>
  <h3>第<%= i %>問 <%= @user_ans[q_attr + 'isCorrect'] ? 'o' : 'x' %> あなたの回答: <%= @user_ans[q_attr + 'yourans'] %> 正解: <%= Question.find(@user_ans[q_attr + 'id'].to_i).correct %> </h3>
<% end %>

<%= link_to  "もう1度10問クイズに挑戦", quiz_path(1) %>

```
resultページは繰り返し処理で簡単に書いてみました〜

最後にroutesを追加します
```ruby:config/routes.rb
  root 'tops#index'
  resources :tops, only: %i[index]
  resources :quizzes
  get '/result' => 'quizzes#result'
```

以上で終わりです！
複雑やったし、セキュリティ的にもまあまあやばそうな気がしてはいるんですけど、実装優先でやってみました〜
誰かの参考になればなと思います！

それでは、ばいちゃ〜〜〜〜

今回の全体コードはこちら〜

https://github.com/naoya25/quiz-rails.git