実行環境
ruby 3.0.2
Rails 7.0.2.3
GitHubはこちら
※Railsのバージョンによって作成されるコードが違う場合があります。適宜ご自身の環境にあわせて読み換えてください。
DB設計
GameとTagが多対多のアソシエーションで結びついている
診断機能の概要
gameに紐づいたタグと、ユーザーが質問に答えた回答がマッチしている数が一番多いものが表示される。
すなわち、gameに[tag1, tag2, tag3, tag4]が紐付いている場合、ユーザーの回答が、[tag1, tag2, tag3, tag5]であったならば、マッチ度は75%として表示される。
ただし、[tag1, tag2, tag3, tag5]というgameが他に存在した場合は、こちらがマッチ度100%として表示される。
アプリケーション作成
必要なモデルを作成しマイグレーション
$ 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を設定
root "games#index"
タグ機能を作成
アソシエーションの追加
class Tag < ApplicationRecord
has_many :tag_games_rerationships, dependent: :destroy
has_many :games, through: :tag_games_rerationships, dependent: :destroy
end
class Game < ApplicationRecord
has_many :tag_games_rerationships, dependent: :destroy
has_many :tags, through: :tag_games_rerationships, dependent: :destroy
end
seedを作成
後述の質問に合わせて作成してください。
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_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 %>
ストロングパラメーターに追加
def game_params
params.require(:game).permit(:name, :discription, tag_ids: [])
end
タグを表示させる
<% game.tags.each do |tag| %>
<span><%= tag.name %></span>
<% end %>
以上で、タグ機能が完成
rails s
で新規投稿してみてください!
診断機能の実装
コントローラーを作成
$ rails g controller diagnoses new index
選択画面を作成
questions
はseedの質問数と一致させる
<% tags = Tag.select(&:name) %>
<% questions = [
# numberはseedで追加したTagの個数と合わせる
{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
へアクセス
一旦、送信されたパラメータを確認
<%= params[:answer] %>
<%= link_to "診断へ", diagnoses_new_path %>
この送られた情報をもとにGameから最もマッチしたレコードを取り出す処理を書く
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
マッチしたレコードとマッチ度を表示させる
マッチ度:
<%= @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 %>
以上で完成です。