mysql + railsでペルソナ5R（ゲーム）のペルソナ情報まとめアプリを作ってみた

# はじめに
railsを使ってゲーム、ペルソナ5Rのペルソナ情報をまとめるアプリケーションを作ってみました。

## なぜやったのか

- railsを使ったwebアプリケーション開発を一通り行ってrailsの理解を深めるため
- jQueryを使ったajax非同期処理の実装方法について学習するため
- セッション管理機能実装について学習するため
- ある程度しっかりしたrspecテストコードを書いてみたかった

開発にあたって以下の項目を最低限組み込みたい機能として設定しました。

- データベース情報検索機能
- データベース情報編集機能
- jQueryによる非同期処理
- ログイン・ログアウトなどのセッション管理
- rspecテストコード

上記の機能実装をするにあたって、ゲームのモンスター情報などをまとめたアプリケーションが良いと考え、ちょうどP5Rにハマっていたということもあり作ってみました。ペルソナ（モンスター）のデータ量も程よかったというのも理由のひとつです。
後述するペルソナ合体（モンスター合体）結果シミュレーター機能については、P5Rにおいて合体法則が明確にルール化されていたので、自分なりにロジックに落とし込んで再現できると思い、挑戦してみた機能になります。

# 環境

- ruby 2.6.5
- rails 6.0.3.4
- mysql 5.7.32

# 画面構成

- ホーム画面
- ペルソナ一覧画面
- ペルソナ詳細画面
- ペルソナ合体結果シミュレーター画面
- ペルソナ情報編集画面

# データベース　テーブル構成

- personas（ペルソナ情報テーブル）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|name   |varchar(255)   |ペルソナ名   |
|arcana_number   |int(11)   |アルカナ番号（arcanasテーブルの外部キー）   |
|category_id   |int(11)   |categoriesテーブルの外部キー   |
|initial_level   |int(11)   |ペルソナ初期レベル   |
|img_path   |varchar(255)   |ペルソナ画像パス   |
- arcanas（アルカナ名・番号マスタテーブル。ペルソナにはそれぞれタロットカードの大アルカナが設定されている。）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|number   |varchar(255)   |アルカナ番号   |
|name   |int(11)   |アルカナ名   |
- categories（ペルソナのカテゴリマスタテーブル。「通常」「宝魔」「集団ギロチン」「DLC」の4種類が登録されている。）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|name   |varchar(255)   |カテゴリ名   |
- skills（ペルソナスキルのテーブル。personasと多対多の関係。）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー  |
|name   |varchar(255)   |スキル名   |
|description   |varchar(255)   |スキル説明文   |
- persona_skills（personasとskillsの中間テーブル）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|persona_id   |int(11)   |personasテーブルの外部キー   |
|skill_id   |int(11)   |skillsテーブルの外部キー   |
|level   |int(11)   |ペルソナがスキルを習得するレベル   |
- arcana_combinations（ペルソナ合体結果を表示するための組み合わせ表テーブル）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|key_number   |varchar(255)   |アルカナ結果を出すためのキーとなる文字列   |
|first_arcana_number   |int(11)   |1体目のアルカナ番号   |
|second_arcana_number   |int(11)   |2体目のアルカナ番号   |
|result_arcana_number   |int(11)   |合体結果のアルカナ番号   |
- users（管理者ユーザー情報テーブル）

|カラム名  |データ型 |カラム説明  |
|:--|:--|:--|
|id   |bigint(20)   |主キー   |
|name   |varchar(255)   |管理者ユーザー名   |
|email   |varchar(255)   |メールアドレス   |
|password_digest   |varchar(255)   |ハッシュ化されたパスワード   |

全てのテーブルには`datetime`型の`created_at` `updated_at`カラムが存在しています。


## ホーム画面

![Screenshot from 2020-12-03 13-12-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/72e767ee-775f-2a65-b5be-4a9da8d8e8da.png)
ホーム画面です。
今回はページのスタイルテーマとして、bootstrap無料テンプレートテーマとfont awesomeを使用しました。

- [SB Admin 2 - Free Bootstrap Admin Theme - Start Bootstrap](https://startbootstrap.com/theme/sb-admin-2)

font awesomeの導入は以下の記事を参考にさせていただきました。

- [RailsでBootstrapとFont-AwesomeはWebpackerで今時っぽく使おう](https://qiita.com/rhistoba/items/f724dae231d7e28bf477)

サイドバーには各ページへのリンクが貼られています。
サイドバー上のアイコンをクリックすることによりホーム画面へ戻ってこれます。
トップバー右の「管理者ログイン」ボタンからログイン画面に遷移します。

ペルソナ情報編集画面へは管理者のみ扱えるようにしています。ログインしていない状態ではサイドバーには表示されていません。
ログインすることで編集機能が使えるという旨のメッセージをホーム画面に表示しています。


## ペルソナ一覧画面

![Screenshot from 2020-12-03 13-42-47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/9401c8c1-39f9-1db0-e50d-21c6597f247c.png)

全232体のペルソナ一覧を表示する一覧画面です。
各ペルソナの情報をテーブル表示しています。
目的のペルソナを検索するための絞り込みフォームも実装しています。検索機能はajaxによる非同期処理で実装しており、「検索」ボタン押下時には画面を再読込することなく絞り込み結果を表示するようにしています。

ペルソナ名部分がリンクになっており、クリックすることでそれぞれのペルソナの詳細画面が別タブで開きます。

## ペルソナ詳細画面

![Screenshot from 2020-12-03 16-19-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/099d89ff-03a4-a08a-c9c7-617ac007e6a1.png)
ペルソナ詳細画面ではペルソナのアルカナ、ペルソナ名、画像、習得スキルが表示されます。
習得スキルにマウスオーバーするとスキル説明がカーソル近くに表示されるようになっています。（javascriptで実装）
![Screenshot from 2020-12-03 16-21-45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/8ae09556-ab31-ee74-edda-e4491416b41a.png)
実装にあたっては以下の記事を参考にさせていただきました。

- [マウスカーソルの隣に吹き出しを表示する | ウェブラボ（株）スタッフブログ](https://www.weblab.co.jp/staff/creator/5209.html)

## ペルソナ合体結果シミュレーター画面

![Screenshot from 2020-12-03 16-32-49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/ccda8262-cb82-f706-904f-19b3328e9557.png)

ペルソナ合体結果シミュレーター画面では、画面についての説明がアコーディオンメニュー形式で書かれている部分と、実際にペルソナを2体選んで合体結果を表示させる部分があります。
ペルソナ5Rにおけるペルソナの合体法則を簡単に説明すると、

1. 合体元ペルソナのアルカナによる組み合わせで誕生するペルソナのアルカナが決まる
2. 「（1体目元ペルソナ初期レベル + 2体目元ペルソナ初期レベル）÷ 2 + 1」で仮レベルが算出される
3. 決定したアルカナと仮レベル以上を満たすペルソナのうち、最も初期レベルの低いペルソナが誕生する

となります。
アルカナの組み合わせ表は以下のリンクを参照です。

- [P5Rアルカナ合体表](https://d2n122k3ikcd8z.cloudfront.net/img/b12eb023-5c4a-4312-b88d-f907d664e832/p5r2gt.png)

アルカナの組み合わせについては法則等がなかった（わからなかった）ので、表の組み合わせを全て「arcana_combinations」テーブルにマスタデータとして保存することで対応しました。
ペルソナを2体選択して「合体」ボタンを押せば、合体結果のペルソナが画面下部に表示されます。ここもajaxによる非同期処理で実装しているので、画面読み込みが発生することなく結果を表示することが可能です。

![Screenshot from 2020-12-03 17-02-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/a5916902-034b-3528-1529-2fbffa359df2.png)

合体結果で表示されたペルソナ名をクリックすることで詳細画面を別タブで開かせることができます。

> ※P5Rをご存知の方に一応補足すると、ゲーム中にある一部の例外的な組み合わせ（シヴァやアリス）や、「宝魔」カテゴリのペルソナの合体には対応していません。

## ペルソナ情報編集画面

ペルソナ情報編集画面ではデータベースに保存されているペルソナ情報を編集することができます。
ペルソナの情報を扱う本アプリケーションでは、ペルソナ情報の編集は全体の機能に大きく影響するので、「users」テーブルに保存されている管理者としてログインした場合のみ扱うことのできる機能としています。
「管理者ログイン」ボタンからログインフォームに遷移し、メールアドレスとパスワードによる認証でセッション管理しています。
![Screenshot from 2020-12-03 17-16-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/83426925-b777-d52b-8df9-bb5292b9e5c7.png)

ログイン周りの機能実装にあたっては以下の記事を参考にさせていただきました。

- [【Rails】ログイン機能を実装する](https://qiita.com/d0ne1s/items/7c4d2be3f53e34a9dec7)

ログインに成功すると「ログインに成功しました」のフラッシュメッセージとともに、サイドバーに「ペルソナ情報編集」のリンクが表示されるようになります。ホーム画面のメッセージも変化します。

![Screenshot from 2020-12-03 17-17-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/3e85dab4-c3cc-7d61-2dd6-bf681b4c0d03.png)

リンクをクリックすることで編集画面に遷移します。

![Screenshot from 2020-12-03 17-22-37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/8f3f6a64-7587-c8ca-b5a1-3b574984df86.png)

railsチュートリアルで見られる編集機能のような頻繁な画面遷移が煩わしいと思ったので、ペルソナ情報編集画面では入力フォームを一覧表示する形式で情報編集ができるようにしてみました。
項目を編集すると、「変更」ボタンが押せるようになって、「変更」を押すと該当情報に対してupdateアクションがはしり、変更が適用されるようになっています。

- 項目に変化があると「変更」ボタンが押せるようになる
![Screenshot from 2020-12-03 17-38-20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/1e441a31-1f59-6787-f789-4c133e4a6154.png)

- 変更が成功するとフラッシュメッセージが表示される
![Screenshot from 2020-12-03 17-38-36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636023/d9c6f1d7-9110-1323-3b78-057c1e5cc99d.png)

編集画面にあたってはログインしている場合のみ使用可能な画面なので、ログインしていない状態からurlをいじる等で遷移できることのないよう、画面遷移時にログインしているかどうか判定を行って、ログインしていなければホーム画面にリダイレクトさせるような機能も実装しています。updateアクション実行時にも同様の判定を行い、ログインしていない状態から不正に編集できることがないようにしています。これらはコントローラーのbefore_actionの機能を使って実現されています。

# rspecテスト

rspecを使ったテストコードも作成してみました。rspecとFactoryBotの導入については以下の記事を参考にさせていただきました。

- [RailsアプリへのRspecとFactory_botの導入手順](https://qiita.com/Ushinji/items/522ed01c9c14b680222c)

今回は以下のようにテストを作成しています。

- モデルテスト
    - Personaモデルテスト
- フィーチャーテスト
    - ペルソナ一覧画面テスト
    - ペルソナ詳細画面テスト
    - 合体結果シミュレーター画面テスト
    - ログイン関連テスト
    - ペルソナ編集画面テスト

テストコードの詳しい内容は省きますが、それぞれのテストシナリオ名とテスト結果が以下のようになっています。

```
ペルソナ編集画面テスト
Capybara starting Puma...
* Version 4.3.6 , codename: Mysterious Traveller
* Min threads: 0, max threads: 4
* Listening on tcp://127.0.0.1:41535
  ログインしているとサイドバーのリンクから編集画面に遷移できる
  ログインしていない状態で編集画面に行こうとするとホーム画面にリダイレクトする
  画面遷移した時にペルソナ情報が表示されている
  初期状態で「変更」ボタンが押せない
  フォームに変化があると「変更」ボタンが押せるようになる
  ペルソナ名が変更できる
  アルカナが変更できる
  初期レベルが変更できる
  種別が変更できる
  変更時に「変更されました」のフラッシュメッセージが出る

ペルソナ一覧画面テスト
  ペルソナ一覧画面に遷移できる
  画面遷移したときにペルソナが表示されている
  ペルソナ名でlike検索ができる
  アルカナで検索ができる
  種別で検索ができる
  デフォルトのソートはアルカナ順である
  初期レベル順でソートができる
  アルカナ順でソートできる

ペルソナ詳細画面テスト
  ペルソナ一覧画面から詳細画面が別タブで開かれる
  ペルソナ名が表示されている
  ペルソナの習得スキルが表示されている

ログイン関連テスト
  ログインしていないとトップ画面に特定のメッセージが表示される
  ログインしていないとサイドバーに「ペルソナ情報編集」リンクが表示されない
  「管理者ログイン」ボタンをクリックするとログイン画面に遷移する
  ログイン画面で「ホーム画面に戻る」ボタンでホーム画面に遷移する
  誤ったフォーム内容だとログインできない
  フォーム内容に誤りがあるとflashメッセージが表示される
  適切なフォーム内容だとログインできる
  ログイン時に「ログインしました」のflashメッセージが表示される
  ログインしているとトップ画面に特定のメッセージが表示される
  ログインしているとサイドバーに「ペルソナ情報編集」リンクが表示される
  ログイン状態から「ログアウト」ボタンをクリックすることでログアウトできる
  ログアウト時に「ログアウトしました」のflashメッセージが表示される

合体結果シミュレーター画面テスト
  合体結果シミュレーター画面に遷移できる
  アコーディオンメニューアイコンをクリックすると、説明欄が表示される
  二体のペルソナを選択して「合体」をクリックすると合体結果のペルソナが表示される
  ペルソナを選択せずに「合体」をクリックするとアラートが出る
  同じペルソナを選択して「合体」をクリックするとアラートが出る
  合体結果ペルソナ名をクリックするとペルソナ詳細画面が別タブで開かれる
  合体不可な組み合わせのペルソナの合体結果は「合体不可」となる

ペルソナモデルテスト
  ペルソナ名でlike検索ができる
  アルカナ番号で検索できる
  カテゴリIDで検索できる
  ペルソナIDから獲得スキル一覧を取得できる
  二体のペルソナの合体結果を取得できる
  「愚者」✕「愚者」は「愚者」を取得する
  「愚者」✕「魔術師」は「死神」を取得する
  合体結果のペルソナは仮レベル以上かつ最も初期レベルが低いものを取得する
  「審判」✕「戦車」はfalseとなる
  「審判」✕「正義」はfalseとなる
  「審判」✕「剛毅」はfalseとなる
  「審判」✕「死神」はfalseとなる

Finished in 26.86 seconds (files took 0.90139 seconds to load)
52 examples, 0 failures
```

# さいごに
今回のアプリケーション開発で、最初に設定した実装したい機能は全て実装できました。rails開発アプリケーションのテーマはなんであれ、最初から最後まで実際に自分で手を動かして開発することで理解が格段に深まることが実感できました。
今回のアプリケーションは練習として作ったものなので公開するということなどは考えていませんが、いつかこういったアプリを開発して公開していけるようになっていきたいですね。

### 次の記事

- [ローカルで開発したアプリケーションをS3、EC2、RDSを使ってとりあえず動かしてみる](https://qiita.com/tetoralynx/items/a8a1ac3ba1076649114d)