0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Ruby on Rails]Railsで診断機能を超簡単に実装する

Last updated at Posted at 2025-02-15

はじめに

本記事ではRailsで簡単に診断機能を作る方法を紹介します。
Viewページを質問の数だけ作成し、if文を使用して前の質問の回答結果に応じて質問を分岐させる簡単な設計です。結果はdb/seeds.rbを使って診断結果を登録し、データベースから取得するようになっています。

注意
この実装方法では診断結果をDBに保存することはできません。
保存したい場合の実装方法も記事後半に載せているので、保存したい場合はそちらも合わせてお読みください

診断の流れ

  • 質問ページ (question1, question2, question3)
  • URLパラメータを使って回答を次のページへ送る
  • 最後に診断結果をデータベースから取得して表示

実装してみよう

Diagnosisモデルの作成

既存のモデルに備え付けるでもいいですし、新しいモデルを作るでもどちらでも構いません。今回は新たにDiagnosisモデルを作成し、実装を進めていくこととします。

コマンドプロンプト
rails generate model Diagnosis result_key:string result_detail:text
rails db:migrate

カラムの役割について説明します。まず、result_keyカラムは最終質問の結果を格納するカラムです。最後の質問の回答結果に「あ」〜「く」の記号(result_key)を割り振っています。もし、結果が「あ」だったらresult_keyに対応する診断結果をDBから取り出します。
続いてresult_detailカラムは診断結果のテキストを格納するカラムです。例えば「診断の結果、あなたには〇〇がおすすめです!」のようなものです。

diagnoses_controller.rbの作成

今度はコントローラーを作成します。作成時に一緒にquestion1.html.erbquestion2.html.erbquestion3.html.erbresult.html.erbも作成しています。
ややこしいですが、diagnosisの複数形はdiagnosesなのでdiagnosesで実装しています

コマンドプロンプト
rails generate controller Diagnoses question1 question2 question3 result

ルーティングの設定 config/routes.rb

設計上質問に行く前に一度1ページ挟みたいとかあれば適宜追記をお願いします!

config/routes.rb
Rails.application.routes.draw do
  get "diagnoses/question1" #追加
  get "diagnoses/question2" #追加
  get "diagnoses/question3" #追加
  get "diagnoses/result" #追加
end

診断データの登録db/seeds.rb

db/seeds.rb
Diagnosis.create([
  { result_key: "あ", result_detail: "あなたにオススメなのは ① です!" },
  { result_key: "い", result_detail: "あなたにオススメなのは ② です!" },
  { result_key: "う", result_detail: "あなたにオススメなのは ③ です!" },
  { result_key: "え", result_detail: "あなたにオススメなのは ④ です!" },
  { result_key: "お", result_detail: "あなたにオススメなのは ⑤ です!" },
  { result_key: "か", result_detail: "あなたにオススメなのは ⑥ です!" },
  { result_key: "き", result_detail: "あなたにオススメなのは ⑦ です!" },
  { result_key: "く", result_detail: "あなたにオススメなのは ⑧ です!" }
])

seedファイルに書き込めたら以下のコマンドを実行します。

コマンドプロンプト
rails db:seed

質問ページquestion.html.erbの作成

以下はあくまで参考までに!自分のアプリの質問項目に変更して使ってね!

question1.html.erb
<h1>診断スタート</h1>
<h2>選ぶなら?</h2>
<a href="/diagnoses/question2?answer=A">Aを選ぶ</a>
<a href="/diagnoses/question2?answer=B">Bを選ぶ</a>
question2.html.erb
<% if params[:answer] == "A" %>
    <h1>Aを選んだあなた</h1>
    <h2>質問その2</h2>
    <a href="/diagnoses/question3?answer=C&prev_answer=<%= params[:answer] %>">Cを選ぶ</a>
    <a href="/diagnoses/question3?answer=D&prev_answer=<%= params[:answer] %>">Dを選ぶ</a>    
<% elsif params[:answer] == "B" %>
    <h1>Bを選んだあなた</h1>
    <h2>質問その2</h2>
    <a href="/diagnoses/question3?answer=E&prev_answer=<%= params[:answer] %>">Eを選ぶ</a>
    <a href="/diagnoses/question3?answer=F&prev_answer=<%= params[:answer] %>">Fを選ぶ</a>

<% end %>

question3.html.erb
<% if params[:answer] == "C" %>
    <h1>Cを選んだあなた</h1>
    <h2>最終質問</h2>
    <a href="/diagnoses/result?answer=あ">オススメ1結果を見る</a>
    <a href="/diagnoses/result?answer=">オススメ2結果を見る</a>
<% elsif params[:answer] == "D" %>
    <h1>Dを選んだあなた</h1>
    <h2>最終質問</h2>
    <a href="/diagnoses/result?answer=">オススメ3結果を見る</a>
    <a href="/diagnoses/result?answer=">オススメ4結果を見る</a>
<% elsif params[:answer] == "E" %>
    <h1>Eを選んだあなた</h1>
    <h2>最終質問</h2>
    <a href="/diagnoses/result?answer=">オススメ5結果を見る</a>
    <a href="/diagnoses/result?answer=">オススメ6結果を見る</a>
<% elsif params[:answer] == "F" %>
    <h1>Fを選んだあなた</h1>
    <h2>最終質問</h2>
    <a href="/diagnoses/result?answer=">オススメ7結果を見る</a>
    <a href="/diagnoses/result?answer=">オススメ8結果を見る</a>
<% end %>

診断結果を取得するresultアクションapp/controllers/diagnoses_controller.rbの作成

診断結果を取得するためのロジックをここに記述します。

diagnoses_controller.rb
def result
  @diagnosis = Diagnosis.find_by(result_key: params[:answer])

  unless @diagnosis
    flash[:alert] = "診断結果が見つかりませんでした"
    redirect_to root_path
  end
end

診断結果ページresult.html.erbの作成

ここに診断結果を表示します。

result.html.erb
<div id="diagnosis">
  <% if @diagnosis.present? %>
    <h2>診断結果</h2>
    <p><%= @diagnosis.result_detail %></p>
  <% else %>
    <p>診断結果が見つかりません</p>
  <% end %>
</div>

以上です!お疲れ様でした!

追記(診断結果をDBに保存したい人向け)

上記のやり方では、View上でparams[:answer]を渡しているため、診断結果はデータベースに保存されません。
単純に一時的に表示させたい場合は問題ありませんが、もし診断結果をDBに保存する必要がある場合は、resultのパラメータをControllerに渡し、適切にデータを保存する必要があります。以下にそのやり方を示します。

変更点:①routes.rbの修正

診断結果をPOSTで送信し、Controllerで処理するようにするため、POST ルートを追加します。

routes.rb
Rails.application.routes.draw do
  get "diagnoses/question1"
  get "diagnoses/question2"
  get "diagnoses/question3"

  # 追加(診断結果を GET でも表示できるようにする)
  get "diagnoses/result", to: "diagnoses#result"

  # 追加(診断結果を POST で送信し、DB に保存する)
  post "diagnoses/result", to: "diagnoses#result"
end

変更点②:diagnoses_controller.rbの修正

診断結果をPOSTで送信し、診断履歴をDBに保存するように修正。
question3アクションとresultアクションを大きく変更しています

diagnoses_controller.rb
def question3
  @question = "最終質問"
  @options = []

  session[:previous_answers] ||= []
  session[:previous_answers] << params[:answer] if params[:answer].present?

  case params[:answer]
  when "C"
    @message = "Cを選んだあなた"
    @options = [
      { text: "オススメ1結果を見る", value: "あ" },
      { text: "オススメ2結果を見る", value: "い" }
    ]
  when "D"
    @message = "Dを選んだあなた"
    @options = [
      { text: "オススメ3結果を見る", value: "う" },
      { text: "オススメ4結果を見る", value: "え" }
    ]
  when "E"
    @message = "Eを選んだあなた"
    @options = [
      { text: "オススメ5結果を見る", value: "お" },
      { text: "オススメ6結果を見る", value: "か" }
    ]
  when "F"
    @message = "Fを選んだあなた"
    @options = [
      { text: "オススメ7結果を見る", value: "き" },
      { text: "オススメ8結果を見る", value: "く" }
    ]
  else
    flash[:alert] = "無効な選択です"
    redirect_to diagnoses_question1_path
  end
end

def result
  if request.post?
    @diagnosis = Diagnosis.find_by(result_key: params[:answer])

    if @diagnosis.nil?
      flash[:alert] = "診断結果が見つかりませんでした"
      redirect_to root_path and return
    end

    # 診断履歴をDBに保存(過去の回答履歴も記録)
    if user_signed_in?
      DiagnosisHistory.create(
        user: current_user, 
        diagnosis: @diagnosis, 
        previous_answers: (session[:previous_answers] || []).join(", ")
      )
    end

    # 診断後はセッションをリセット
    session[:previous_answers] = []

    redirect_to diagnoses_result_path(answer: params[:answer])
  else
    @diagnosis = Diagnosis.find_by(result_key: params[:answer])

    if @diagnosis.nil?
      flash[:alert] = "診断結果が見つかりませんでした"
      redirect_to root_path and return
    end

    render :result
  end
end

  • POSTリクエストを受け付けて診断結果を処理できるようにした
  • DiagnosisHistory.createを追加し、診断結果をデータベースに保存できるようにした
  • redirect_to diagnoses_result_path(answer: params[:answer])を追加し、診断後に GETで結果ページを表示するようにした

変更点③:question3.html.erbの修正

診断結果の選択をGETではなくPOSTで送信するように修正。

question3.html.erb
<h1><%= @message %></h1>
<h2><%= @question %></h2>

<% @options.each do |option| %>
  <%= form_with url: diagnoses_result_path, method: :post, local: true do %>
    <%= hidden_field_tag :answer, option[:value] %>
    <%= submit_tag option[:text] %>
  <% end %>
<% end %>

変更点④:DiagnosisHistoryモデルの追加

DiagnosisHistory をデータベースで管理するために、モデルを作成し、マイグレーションを適用する必要がありました...
以下のコマンドを実行して、DiagnosisHistory モデルを作成します。

rails generate model DiagnosisHistory user:references diagnosis:references previous_answers:text
rails db:migrate

Userモデルなどある場合はリレーションも忘れず行ってください!

まとめ

ルーティングではpost "diagnoses/result" を追加、ControllerはPOSTで診断結果を受け取り、DB に保存。質問ページ (question3.html.erb) はPOSTでフォーム送信し、診断結果ページ (result.html.erb)で@diagnosisを使って表示するという流れで実装しました。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?