LoginSignup
5
6

Rails 診断機能を実装する タグ機能 マッチ度判断

Last updated at Posted at 2022-06-06

実行環境

ruby 3.0.2
Rails 7.0.2.3

GitHubはこちら

※Railsのバージョンによって作成されるコードが違う場合があります。適宜ご自身の環境にあわせて読み換えてください。

DB設計

image.png

GameとTagが多対多のアソシエーションで結びついている

診断機能の概要

gameに紐づいたタグと、ユーザーが質問に答えた回答がマッチしている数が一番多いものが表示される。
すなわち、gameに[tag1, tag2, tag3, tag4]が紐付いている場合、ユーザーの回答が、[tag1, tag2, tag3, tag5]であったならば、マッチ度は75%として表示される。
ただし、[tag1, tag2, tag3, tag5]というgameが他に存在した場合は、こちらがマッチ度100%として表示される。

アプリケーション作成

必要なモデル、DB等を作成

$ rails new diagnose_games
$ cd diagnose_games
$ rails g scaffold Game name:string discription:text
$ rails g model Tag name:string
$ rails g model TagGamesRerationship game:references tag:references
$ rails db:migrate

root_pathを設定

route.rb
root "games#index"

タグ機能を作成

アソシエーションの追加

tag.rb
class Tag < ApplicationRecord
  has_many :tag_games_rerationships, dependent: :destroy
  has_many :games, through: :tag_games_rerationships, dependent: :destroy
end
game.rb
class Game < ApplicationRecord
  has_many :tag_games_rerationships, dependent: :destroy
  has_many :tags, through: :tag_games_rerationships, dependent: :destroy
end

seedを作成
後述の質問に合わせて作成してください。

seed.rb
Tag.create!([
  { name: '2人' },
  { name: '3人' },
  { name: '4人' },
  { name: '5人以上' },
  { name: '家族' },
  { name: '友達' },
  { name: '恋人' },
  { name: 'まったり' },
  { name: '飲み会' },
  { name: '白熱' },
  { name: 'おもしろ' },
  { name: '小/中学生' },
  { name: '高校/大学生' },
  { name: '社会人' },
  { name: '30分以下' },
  { name: '30〜1時間' },
  { name: '1時間以上' },
  { name: 'ブラフ'},
  { name: '正体隠匿'},
  { name: 'タイル配置'},
  { name: '拡大再生産'},
  { name: 'ドラフト'},
  { name: 'ワーカープレイスメント'},
  { name: '陣取り'},
  { name: 'デッキ構築'},
  { name: '競り'},
  { name: '協力'},
  { name: '表現'},
  { name: 'アクション'},
])
$ rails db:seed

タグの入力を追加

_form.html.erb
  <%= form_with(model: game) do |form| %>
  <% if game.errors.any? %>
    <div style="color: red">
      <h2><%= pluralize(game.errors.count, "error") %> prohibited this game from being saved:</h2>

      <ul>
        <% game.errors.each do |error| %>
          <li><%= error.full_message %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <div>
    <%= form.label :name, style: "display: block" %>
    <%= form.text_field :name %>
  </div>

  <div>
    <%= form.label :discription, style: "display: block" %>
    <%= form.text_area :discription %>
  </div>
↓追記
  <div class='form-group'>
    <%= form.collection_check_boxes(:tag_ids, Tag.all, :id, :name) do |tag| %>
      <div class='form-check'>
        <%= tag.label class: 'form-check-label' do %>
          <%= tag.check_box class: 'form-check-input' %>
          <%= tag.text %>
        <% end %>
      </div>
    <% end %>
  </div>
↑ここまで

  <div>
    <%= form.submit %>
  </div>
<% end %>

image.png

ストロングパラメーターに追加

games_controller.rb
    def game_params
      params.require(:game).permit(:name, :discription, tag_ids: [])
    end

タグを表示させる

_game.html.erb
  <% game.tags.each do |tag| %>
    <span><%= tag.name %></span>
  <% end %>

以上で、タグ機能が完成
rails sで新規投稿してみてください!
image.png

診断機能の実装

コントローラーを作成

$ rails g controller diagnoses new index

選択画面を作成
questionsはseedの質問数と一致させる

app/views/diagnoses/new.html.erb
<% tags = Tag.select(&:name) %>
<% questions = [
  {title: "何人で遊びますか?", number: 4},
  {title: "誰と遊びますか?", number: 3},
  {title: "シチュエーションは?", number: 4},
  {title: "遊ぶ人の世代は?", number: 3},
  {title: "プレイ時間は?", number: 3},
  {title: "ゲームの種類は?", number: 12},
] %>
<% question_id = Tag.first.id %>

<%= form_tag diagnoses_index_path, method: :get do %>
  <% questions.each do |q| %>
    <div class="question-container">
      <%= q[:title] %>
      <% tags.shift(q[:number]).each do |t| %>
        <input type="checkbox" id="checkbox<%= question_id %>" name="answer[]" value="<%= question_id %>" >
        <label for="checkbox<%= question_id %>"><%= t.name %></label>
        <% question_id += 1 %>
      <% end %>
    </div>
  <% end %>
  <%= submit_tag %>
<% end %>

http://localhost:3000/diagnoses/newへアクセス

image.png

一旦、送信されたパラメータを確認

app/views/diagnoses/index.html.erb
<%= params[:answer] %>

<%= link_to "診断へ", diagnoses_new_path %>

image.png

この送られた情報をもとにGameから最もマッチしたレコードを取り出す処理を書く

diagnoses_controller.rb
  def index
    games = Game.all
    selected_tag_ids = params[:answer]
    @mach_tag_count = 0
    tmp_mach_tag_count = 0
    @mached_games = []

    games.each do |game|
      tmp_mach_tag_count = 0
      game.tags.each do |tag|
        if selected_tag_ids&.include?(tag.id.to_s)
          tmp_mach_tag_count = tmp_mach_tag_count + 1 
        end
      end

      if @mach_tag_count < tmp_mach_tag_count
        @mached_games = []
        @mached_games << game
        @mach_tag_count = tmp_mach_tag_count
      elsif @mach_tag_count == tmp_mach_tag_count
        @mached_games << game
      end
    end
  end

マッチしたレコードとマッチ度を表示させる

app/views/diagnoses/index.html.erb
マッチ度:
<%= @mach_tag_count.to_f / params[:answer].length.to_f * 100 %> %

<% @mached_games.each do |game| %>
  <div class="game-container">
    Game名:<%= game.name %><br>
    説明:<%= game.discription %><br>
    タグ:
    <% game.tags.each do |tag| %>
      <%= tag.name %>
    <% end %>
  </div>
<% end %>

<%= link_to "診断へ", diagnoses_new_path %>
<%= link_to "New game", new_game_path %>

image.png

以上で完成です。

5
6
3

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
5
6