toke04 / ruby-flash-card

3 stars 0 forks source link

リソース設計 #14

Closed toke04 closed 1 year ago

toke04 commented 1 year ago

ペーパープロトタイプ

https://bootcamp.fjord.jp/products/16181

リソース

最終的なリソース設計

Method Path Description
GET / トップ画面を表示(ログインしていればメソッドの一覧画面を、ログインしていなければトップページを表示する) こちらのページから、omniauthを利用し、GitHub認証登録・ログインを実装する
GET /ruby_modules 管理者用モジュール(クラス)の一覧画面
POST ruby_modules 管理者用モジュール(クラス)の新規登録
GET /ruby_modules/new 管理者用モジュール(クラス)の新規登録画面
GET /ruby_modules/id/edit 管理者用モジュール(クラス)の編集画面
PATCH /ruby_modules/id 管理者用モジュール(クラス)の更新
DELETE /ruby_modules/id 管理者用モジュール(クラス)の削除
GET /ruby_methods 管理者用メソッドの一覧画面
POST /ruby_methods 管理者用メソッドの新規登録
GET /ruby_methods/new 管理者用メソッドの新規登録画面
GET /ruby_methods/id/edit 管理者用メソッドの編集画面
PATCH /ruby_methods/id 管理者用メソッドの更新
DELETE /ruby_methods/id 管理者用メソッドの削除
GET /user_ruby_methods 一般ユーザー用メソッドの一覧画面
POST /user_ruby_methods 一般ユーザー用メソッドの新規登録
GET /user_ruby_methods/id/edit 一般ユーザー用メソッドの編集画面 ※memo(メソッドの説明) & rememberedしか更新できないようにします
PATCH /user_ruby_methods/id 一般ユーザー用メソッドの更新
DELETE /user_ruby_methods/id 一般ユーザー用メソッドの削除
GET /flash_card/new クイズの設定画面
GET /flash_card/show 一つのクイズを新規作成し、HTMLファイルを返却。 クイズはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される
POST /auth/github/callback GitHub認証。登録・ログインを処理する
DELETE /logout ログアウトの実行
過去のリソース | Method | Path | Description | | ------ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | GET | / | トップ画面を表示(ログインしていればメソッドの一覧画面`/methods`に遷移、ログインしていなければトップページを表示する)
こちらのページから、omniauthを利用し、GitHub認証登録・ログインを実装する | | GET | /methods | メソッドの一覧画面 | | POST | /methods | メソッドの新規登録 | | GET | /methods/new | メソッドの新規登録画面 | | GET | /methods/id/edit | メソッドの編集画面 | | PATCH | /methods/id | メソッドの更新 | | DELETE | /methods/id | メソッドの削除 | | GET | /quiz/new | クイズの設定画面 | | POST | /quiz | クイズの新規作成(DB上のリソースは作らない) | | GET | /quiz | 一つ一つのクイズ(クイズはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される) | | POST | /auth/github/callback | GitHub認証。登録・ログインを処理する | | GET | /me | ユーザーのプロフィールを表示 | | DELETE | /logout | ログアウトの実行 | | DELETE | /retirement | 退会処理 |

説明

このアプリの主な機能は methodsquizです。

methods

railsのresourcesを使ったRESTfulなapiで作ります。 GET /methods以外は、railsの標準的な機能で作るのですが、 GET /methodsはreactを使って構築する予定です。 railsはデータベースから、ユーザーに紐づいたmethodsの全てを取得し、 reactにデータを渡し、reactはstateで状態管理します

[/methodsでreactが管理するデータ]

methods = [] // map,each_with_indexみたいのが格納されている。これをmapで展開する
visibility = "all",  // {all: 全て表示、remembered:覚えたものを表示、notRemembered:覚えてないものを表示}のような絞り込みを、reactで行う予定
language = "ruby" // 言語が指定されている場合、reactでこちらも絞り込む(`method.language`にアクセスする事で絞り込める)
page = 0 // ページネーションの何番目にいるか

vite_railsを使って、railsからreactにデータを渡し、呼び出します

検索の絞り込みは、reactで管理している値を利用し、リクエストを送らず描画します。

[/methods] Image

quiz

クイズは、DB上ではリソースを持ちません。 最初にクイズの設定画面である/quiz/newにアクセスし、 ユーザーが設定を入力後、POST /quizにリクエストを送ります。 その値を利用し、methodsテーブルから言語に応じたメソッドを一つ取得し、

をboolean(表示・非表示フラグ)で管理した値と合わせて、GET /quizに渡します。

[/quiz/new] Image

次のクイズに行く際の説明

次のクイズに行く際は、こちらの写真の右下の「次の問題」というボタンをクリックすると、次のクイズが出題されます。 [/quiz] Image

次のクイズを出題するために、

name :true
operation_detail :false
use_case :false
language : "ruby"

のような値も合わせて、POST /quizにリクエスト送ります。 この値を利用して、先ほど説明した処理を行います。

ちなみに、URLからGET /quizを直打ちした場合は、デフォルトで

name :true
operation_detail :false
use_case :false
language : "ruby" # 上の処理で取得したメソッドのlanguageが入る

GET /quizに渡し、クイズを作成します。

GET /quizはreactで作成します。 管理するデータは以下です

[/quizでreactが管理するデータ]

method = [] // each_with_index等のメソッドが一つ格納されています
name :true
operation_detail :false
use_case :false
language = "ruby"

この値を利用し、

というのを繰り返します

yuuu commented 1 year ago

@syo-tokeshi 確認しました 👍 気になった点をいくつかコメントしますね。

toke04 commented 1 year ago

クイズ個別の画面は1つのエンドポイントでReactを用いて、出題→回答を繰り返していくイメージを持ちました

はい、その通りです😊

出題するクイズの情報は予めDOMに埋め込んでおくのでしょうか?それともAPIを使ってバックエンドから取得しますか?

DOMに埋め込んでおく実装にします🙇‍♂️

POST /quizにリクエストを送ると、このような値が返却されるので

method = [id, user_id, language, name, operation_detail, use_case, remembered] # methodsテーブルのレコードが一つ入る
name :true
operation_detail :false
use_case :false
language : "ruby" 

それをそのままstateとしてデータを保有して、ユーザーが「回答をみる」というボタンを押したら表示できるようにします

保存

[吹き出しの部分は、「回答をみる」のボタンを押すことで、display noneからdisplay blockになり、表示される]

保存2
toke04 commented 1 year ago

クイズはひたすら /quiz へのPOST→GETを繰り返すものなので、終了画面のようなものはない理解であっていますか?

はい、その通りです🙇‍♂️

methodsテーブルからremembered = falseのレコードが無かったら、この画面を出力させる予定です🙇‍♂️

スクリーンショット 2023-06-23 10 13 17
toke04 commented 1 year ago

クイズの画面に「前の問題」というボタンがありますが、どうやって前の問題を表示するのかが気になりました。

ここはyuuuさんにも聞きたいのですが、

ことが出来ますでしょうか?🙇‍♂️(直前に描画したHTMLを表示したい。リクエストを送り直したくない)

文字

もし出来ない場合は、

で対応しようと思います🙇‍♂️

直前のデータをreactのstate or localStorageで管理する事も可能だと思いましたが、「前の問題」という機能はそこまで欲しくないので、その場合は削除しようと思います🙇‍♂️

yuuu commented 1 year ago

history.back() で戻ることはできますが、あくまでブラウザの履歴情報を元に前の画面を描画しているだけなので、意図的に履歴を削除されている場合は表示できない(orリロードが発生する)懸念はあります。あと、 history.back() するならブラウザの戻るボタンと同じ挙動になるはずなので、ボタンを設置する意味はあまりないかもしれませんね。

yuuu commented 1 year ago

POST /quiz について、コメントを見る限り非同期でのリクエストに見えたのですが認識あっていますでしょうか?

もし非同期でのリクエストだとすると以下が気になりました。

toke04 commented 1 year ago

history.back() で戻ることはできますが、あくまでブラウザの履歴情報を元に前の画面を描画しているだけなので、意図的に履歴を削除されている場合は表示できない(orリロードが発生する)懸念はあります。あと、 history.back() するならブラウザの戻るボタンと同じ挙動になるはずなので、ボタンを設置する意味はあまりないかもしれませんね。

了解しました。 色々考えた結果、戻るボタンはメリットがあまりないと思ったので削る事にします🙇‍♂️

回答ありがとうございました😄

toke04 commented 1 year ago

POST /quiz について、コメントを見る限り非同期でのリクエストに見えたのですが認識あっていますでしょうか?

すみませ、リソース設計を見直し、POST /quizを廃止し、以下の二つのURIでクイズ機能を作るよう、変更します

GET /quiz/new クイズの設定画面
GET /quiz 一つのクイズを新規作成し、HTMLファイルを返却。
クイズはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される

処理としては普通のrailsのhttpのgetメソッドと同じ感じになり、GET | /quizにリクエストが来た際は以下のようなプログラムが走るようにします🙇‍♂️

def quiz
    @language = params[:language]
    @name = params[:name] || true
    @operation_detail = params[:operation_detail] || false
    @use_case = params[:use_case] || false
    if @language
      @method = Methods.where(user_id: current_user.id, remembered: false, language: @language)&.sample
    else
      @method = Methods.where(user_id: current_user.id, remembered: false)&.sample
    end
end

このようなコントローラーの設定にすると、

にも、ちゃんと対応してHTMLを描画出来ると考えております🙇‍♂️

また、vite_railsを利用し、このようにreactにコントローラーのデータを渡す予定です https://tech.fusic.co.jp/posts/2022-07-07-vite-rails-react/

<%= content_tag :div, "", id: "quiz", data: { language: @language, name: @name, operation_detail: @operation_detail, use_case: @use_case, method: @method  }  %>
<%= vite_javascript_tag 'quiz.tsx' %>

また、出題出来るクイズがあるかないかは@methodに値があるかないかで決まるのですが、 quiz/quiz.erbで以下のような条件分岐でHTMLを描画するつもりです

[簡易サンプル]

if @method
    <%= content_tag :div, "", id: "quiz", data: { language: @language, name: @name, operation_detail: @operation_detail, use_case: @use_case, method: @method  }  %>
    <%= vite_javascript_tag 'quiz.tsx' %>
else
    <p>全てのクイズが出題されました。</p>
    <a>メソッド一覧へ</a><a>再度クイズに挑戦</a>
end

[修正後リソース設計] Method Path Description
GET / トップ画面を表示(ログインしていればメソッドの一覧画面を、ログインしていなければトップページを表示する)
こちらのページから、omniauthを利用し、GitHub認証登録・ログインを実装する
GET /methods メソッドの一覧画面
POST /methods メソッドの新規登録
GET /methods/new メソッドの新規登録画面
GET /methods/id/edit メソッドの編集画面
PATCH /methods/id メソッドの更新
DELETE /methods/id メソッドの削除
GET /quiz/new クイズの設定画面
GET /quiz 一つのクイズを新規作成し、HTMLファイルを返却。
アクションはquizにする。(クイズはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される)
POST /auth/github/callback GitHub認証。登録・ログインを処理する
GET /me ユーザーのプロフィールを表示
DELETE /logout ログアウトの実行
DELETE /retirement 退会処理
yuuu commented 1 year ago

回答ありがとうございます。 GET /quiz にアクセスすればクイズが表示され、リロードすればランダムに問題が変わる、という仕様にするということですね。

その場合、今度は「覚えた!」をどうやってDBに反映するかが問題になりそうですが何か策はありますでしょうか? また、クイズが完了した後の「再度クイズに挑戦」についても、どうやって「全てのクイズを覚えた状態」からリセットするのかが気になりました。

toke04 commented 1 year ago

@yuuu

その場合、今度は「覚えた!」をどうやってDBに反映するかが問題になりそうですが何か策はありますでしょうか?

クイズを出題する際、react側では以下のようなデータを保有しております。

method : [id, user_id, language, name, operation_detail, use_case, remembered] # methodsテーブルのレコードが一つ入る
name :true
operation_detail :false
use_case :false
language : "ruby" 

methodが持っているidを利用して、 以下のようにリクエストを送ります

https://github.com/fjordllc/bootcamp/blob/324ddb7b53af5fbb7b531cb3c42dcc08a8eece2d/app/javascript/components/Tags/TagEditModal.jsx#L23

const updateMethod = () => {
    fetch(`/methods/${method.id}`, {
      method: 'PUT',
      headers: {
        'Content-Type': 'application/json; charset=utf-8',
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRF-Token': CSRF.getToken()
      },
      credentials: 'same-origin',
      redirect: 'manual',
      body: JSON.stringify({ method: { remembered: true } })
    })
      .then(() => {
        toast('メソッドを「覚えた」に移動させました')
        updateTagList()
      })
      .catch((error) => {
        console.warn(error)
      })
  }

それにより、メソッドをDB上で「覚えた!」に移動させることが可能になります🙇‍♂️ ユーザーにはtoastでメソッドの移動が完了したらお知らせします🙇‍♂️

toke04 commented 1 year ago

また、クイズが完了した後の「再度クイズに挑戦」についても、どうやって「全てのクイズを覚えた状態」からリセットするのかが気になりました。

はい、こちらに関して、まずクイズが出題される条件を提示します。

  1. languageに関係なく、remembered がfalseであるmethodsテーブルのレコードがあれば良い

になります。

なので、

を、上記の条件を満たしている場合のみ表示します🙇‍♂️ そして、満たしていない場合、GET /quizの画面のリンクを以下に変更します

[出題できるクイズがない場合の画面]

スクリーンショット 2023-06-26 10 58 03

[出題できるクイズがある場合の画面]

スクリーンショット 2023-06-26 10 53 16

この表示により、ユーザーに出題できるクイズがない場合は、新しいメソッドを追加してもらうことを促します🙇‍♂️

yuuu commented 1 year ago

なるほど PATCH | /methods/id はAPIとしても実行可能とする設計なのですね 👍 であれば問題なさそうです。

toke04 commented 1 year ago

@yuuu お疲れ様です。 DB設計変更に伴って URL(リソース)も設計し直しました🙇‍♂️ ご確認よろしくお願いいたします🙇‍♂️

[routes.rb]

  resources :user_ruby_methods
  resources :ruby_methods
  get 'ruby_quiz/new'
  get 'ruby_quiz/show'
Method Path Description
GET / トップ画面を表示(ログインしていればメソッドの一覧画面を、ログインしていなければトップページを表示する)こちらのページから、omniauthを利用し、GitHub認証登録・ログインを実装する
GET /ruby_methods 管理者用メソッドの一覧画面
POST /ruby_methods 管理者用メソッドの新規登録
GET /ruby_methods/new 管理者用メソッドの新規登録画面
GET /ruby_methods/id/edit 管理者用メソッドの編集画面
PATCH /ruby_methods/id 管理者用メソッドの更新
DELETE /ruby_methods/id 管理者用メソッドの削除
GET /user_ruby_methods 一般ユーザー用メソッドの一覧画面
POST /user_ruby_methods 一般ユーザー用メソッドの新規登録
GET /user_ruby_methods/new 一般ユーザー用メソッドの新規登録画面
GET /user_ruby_methods/id/edit 一般ユーザー用メソッドの編集画面 ※description(メソッドの説明) & rememberedしか更新できないようにします
PATCH /user_ruby_methods/id 一般ユーザー用メソッドの更新
DELETE /user_ruby_methods/id 一般ユーザー用メソッドの削除
GET /ruby_quiz/new クイズの設定画面
GET /ruby_quiz 一つのクイズを新規作成し、HTMLファイルを返却。アクションはshowにする。(クイズはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される)
POST /auth/github/callback GitHub認証。登録・ログインを処理する
GET /me ユーザーのプロフィールを表示
DELETE /logout ログアウトの実行
DELETE /retirement 退会処理
toke04 commented 1 year ago

DB設計にも説明を貼りましたが、同じ説明を貼ります🙇‍♂️

説明

管理者のみが閲覧できるrubyのメソッド一覧を確認する画面http://localhost:3000/ruby_methodsこちらに、 メソッドを登録する画面であるhttp://localhost:3000/ruby_methods/newのリンクがあり、メソッドを登録していきます

[index画面には登録したメソッド一覧と、新しいrubyのメソッドを登録するボタンが設置されている] スクリーンショット_2023-07-10_17_19_11

[こちらが新しくメソッドを追加するhttp://localhost:3000/ruby_methods/newになり、管理者である私がカテゴリーとメソッド名を入力することでメソッドが追加される] スクリーンショット 2023-07-10 17 24 52

スクリーンショット 2023-07-10 17 24 30

[登録すると自動でURLが生成される] スクリーンショット 2023-07-10 17 27 13

[一般ユーザー用のrubyメソッド一覧画面 http://localhost:3000/user_ruby_methods] スクリーンショット 2023-07-10 17 29 30

[管理者(私)が登録したメソッドに対し、ユーザーが説明を入れるhttp://localhost:3000/user_ruby_methods/new] スクリーンショット 2023-07-10 17 30 51

[リンクを踏むと公式に飛べる。ユーザーは正しい情報を確認しながらメソッドを覚えられる] スクリーンショット 2023-07-10 17 31 46

[クイズの設定画面 http://localhost:3000/ruby_quiz/new 先ほどユーザーが登録したメソッドをクイズで確かめることができる] スクリーンショット 2023-07-10 17 34 58

[ユーザーがクイズに答える画面http://localhost:3000/ruby_quiz/show] スクリーンショット 2023-07-10 17 36 49

[「回答を見る」ボタンを押すと、このように前回の答えと、公式のリンクがあり、確かめることが出来る。 また、今回の内容の方が良かったら「内容を更新する」ボタンで更新できる。 また、「おぼえた!」ボタンを押すとおぼえた!に移動し、復習モードで復習できる。] スクリーンショット 2023-07-10 17 39 00

toke04 commented 1 year ago

町田さんと話あった結果のリソース設計

@yuuu お疲れ様です。 町田さんと話し合った結果、以下の設計になりました🙇‍♂️

Method Path Description
GET / トップ画面を表示(ログインしていればメソッドの一覧画面を、ログインしていなければトップページを表示する)
こちらのページから、omniauthを利用し、GitHub認証登録・ログインを実装する
GET /ruby_methods 管理者用メソッドの一覧画面
POST /ruby_methods 管理者用メソッドの新規登録
GET /ruby_methods/new 管理者用メソッドの新規登録画面
GET /ruby_methods/id/edit 管理者用メソッドの編集画面
PATCH /ruby_methods/id 管理者用メソッドの更新
DELETE /ruby_methods/id 管理者用メソッドの削除
GET /user_ruby_methods 一般ユーザー用メソッドの一覧画面
POST /user_ruby_methods 一般ユーザー用メソッドの新規登録
GET /user_ruby_methods/id/edit 一般ユーザー用メソッドの編集画面 ※memo(メソッドの説明) & rememberedしか更新できないようにします
PATCH /user_ruby_methods/id 一般ユーザー用メソッドの更新
DELETE /user_ruby_methods/id 一般ユーザー用メソッドの削除
GET /flash_card/new フラッシュカードの設定画面
GET /flash_card/show 一つのフラッシュカードを新規作成し、HTMLファイルを返却。
アクションはshowにする。(フラッシュカードはDBでリソースを作らないので、idを持たない。毎回ランダムで作成される)
POST /auth/github/callback GitHub認証。登録・ログインを処理する
DELETE /logout ログアウトの実行
DELETE /retirement 退会処理
toke04 commented 1 year ago

また、ユーザーがクイズするメソッドのデータは、seedファイルに記載し、一気に流し込む予定です。

https://github.com/syo-tokeshi/pra-method-quiz/blob/main/db/seeds.rb#L35-L61

サンプル

def create_url(name)
  category, name = name.split('#')
  if Net::HTTP.get_response(URI.parse("https://docs.ruby-lang.org/ja/latest/method/#{category}/i/#{name}.html")).code == '200'
    "https://docs.ruby-lang.org/ja/latest/method/#{category}/i/#{name}.html"
  else
    "https://docs.ruby-lang.org/ja/latest/class/#{category}.html#I_#{name.upcase.slice(/[^?]+/)}--3F"
  end
end

dir_methods = %w[children close each each_child fileno inspect path pos pos= read rewind seek tell to_path]
      .map do |item|
  "Dir##{item}"
end

dir_methods.each do |name|
  RubyMethod.create([
                      name: name.split('#')[1],
                      category: name.split('#')[0],
                      official_url: create_url(name)
                    ])
end

URLもほぼ問題なく設定できておりました🙇‍♂️ 本番環境で稼働後は、管理画面から微調整をする予定です🙇‍♂️

yuuu commented 1 year ago

見直しありがとうございます。いくつかコメントします。

toke04 commented 1 year ago

@yuuu

「一般ユーザー用メソッドの新規登録画面」のURIが漏れてそうです

こちらなのですが、新しいUIでは、クイズの中で登録を行うことになりました。

  1. 「知らない」 or 「知ってる」ボタンを押すと、user_ruby_methodsテーブルのレコードが作成される(その際rememberedの値はボタンに応じて入る)
  2. textareaに入力後「保存する」ボタンをすると、memoのカラムが更新される スクリーンショット 2023-07-13 10 16 54

スクリーンショット 2023-07-13 10 18 03

クイズの画面で「知っている」「知らない」を選択することで、 user_ruby_methods テーブルの remembered が更新される認識ですが、POSTまたはPUT用のURIは不要でしょうか?

既存の POST /user_ruby_methods 一般ユーザー用メソッドの新規登録
PATCH /user_ruby_methods/id 一般ユーザー用メソッドの更新
-- -- --

で対応出来るのかな、と思っているのですが、もし難しそうな場合は、 POSTまたはPUT用のURIを追加しようと思います🙇‍♂️

yuuu commented 1 year ago

なるほど。クイズでは予めユーザーがリストアップしたメソッドのみが出題されるのかなと推測していましたが、このシステムに登録されている全メソッドのうち、そのユーザーがまだ覚えていないものが出題される認識で合っていますでしょうか?

toke04 commented 1 year ago

なるほど。クイズでは予めユーザーがリストアップしたメソッドのみが出題されるのかなと推測していましたが、このシステムに登録されている全メソッドのうち、そのユーザーがまだ覚えていないものが出題される認識で合っていますでしょうか?

クイズに挑戦する条件なのですが、このような仕様を想定してます

  1. 「まだ挑戦してないメソッド」が残っている場合は、ラジオボタンのデフォルトにして、この条件で答えてもらうことにする
  2. 「まだ挑戦してないメソッド」が完了した場合(この写真の例だと100/100になる)は、「まだ挑戦してないメソッド」のラジオボタンが消え、

のどちらかを選択してもらって、クイズに挑戦してもらう、という仕様になります🙇‍♂️

[メソッドに対する覚えたか覚えてないかを管理する、enumのデータ型]

[クイズ出題画面]

スクリーンショット 2023-07-14 9 51 10
yuuu commented 1 year ago

回答ありがとうございます 👍 納得しました。 このリソース設計で大丈夫そうですね!