Closed toke04 closed 1 year ago
@syo-tokeshi 確認しました 👍 気になった点をいくつかコメントしますね。
/quiz
へのPOST→GETを繰り返すものなので、終了画面のようなものはない理解であっていますか?クイズ個別の画面は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
になり、表示される]
クイズはひたすら /quiz へのPOST→GETを繰り返すものなので、終了画面のようなものはない理解であっていますか?
はい、その通りです🙇♂️
methods
テーブルからremembered = false
のレコードが無かったら、この画面を出力させる予定です🙇♂️
クイズの画面に「前の問題」というボタンがありますが、どうやって前の問題を表示するのかが気になりました。
ここはyuuuさんにも聞きたいのですが、
history.back();
メソッドで、GET /quiz
から直前のGET /quiz
に戻ることが出来ますでしょうか?🙇♂️(直前に描画したHTMLを表示したい。リクエストを送り直したくない)
もし出来ない場合は、
で対応しようと思います🙇♂️
直前のデータをreactのstate or localStorageで管理する事も可能だと思いましたが、「前の問題」という機能はそこまで欲しくないので、その場合は削除しようと思います🙇♂️
history.back()
で戻ることはできますが、あくまでブラウザの履歴情報を元に前の画面を描画しているだけなので、意図的に履歴を削除されている場合は表示できない(orリロードが発生する)懸念はあります。あと、 history.back()
するならブラウザの戻るボタンと同じ挙動になるはずなので、ボタンを設置する意味はあまりないかもしれませんね。
POST /quiz
について、コメントを見る限り非同期でのリクエストに見えたのですが認識あっていますでしょうか?
もし非同期でのリクエストだとすると以下が気になりました。
history.back()
で戻ることはできますが、あくまでブラウザの履歴情報を元に前の画面を描画しているだけなので、意図的に履歴を削除されている場合は表示できない(orリロードが発生する)懸念はあります。あと、history.back()
するならブラウザの戻るボタンと同じ挙動になるはずなので、ボタンを設置する意味はあまりないかもしれませんね。
了解しました。 色々考えた結果、戻るボタンはメリットがあまりないと思ったので削る事にします🙇♂️
回答ありがとうございました😄
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
このようなコントローラーの設定にすると、
/quiz
にアクセスした場合にも、ちゃんと対応して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 | 退会処理 |
回答ありがとうございます。
GET /quiz
にアクセスすればクイズが表示され、リロードすればランダムに問題が変わる、という仕様にするということですね。
その場合、今度は「覚えた!」をどうやってDBに反映するかが問題になりそうですが何か策はありますでしょうか? また、クイズが完了した後の「再度クイズに挑戦」についても、どうやって「全てのクイズを覚えた状態」からリセットするのかが気になりました。
@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を利用して、 以下のようにリクエストを送ります
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でメソッドの移動が完了したらお知らせします🙇♂️
また、クイズが完了した後の「再度クイズに挑戦」についても、どうやって「全てのクイズを覚えた状態」からリセットするのかが気になりました。
はい、こちらに関して、まずクイズが出題される条件を提示します。
になります。
なので、
を、上記の条件を満たしている場合のみ表示します🙇♂️
そして、満たしていない場合、GET /quiz
の画面のリンクを以下に変更します
[出題できるクイズがない場合の画面]
[出題できるクイズがある場合の画面]
この表示により、ユーザーに出題できるクイズがない場合は、新しいメソッドを追加してもらうことを促します🙇♂️
なるほど PATCH | /methods/id
はAPIとしても実行可能とする設計なのですね 👍 であれば問題なさそうです。
@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 | 退会処理 |
DB設計にも説明を貼りましたが、同じ説明を貼ります🙇♂️
管理者のみが閲覧できるrubyのメソッド一覧を確認する画面http://localhost:3000/ruby_methods
こちらに、
メソッドを登録する画面であるhttp://localhost:3000/ruby_methods/new
のリンクがあり、メソッドを登録していきます
[index画面には登録したメソッド一覧と、新しいrubyのメソッドを登録するボタンが設置されている]
[こちらが新しくメソッドを追加するhttp://localhost:3000/ruby_methods/new
になり、管理者である私がカテゴリーとメソッド名を入力することでメソッドが追加される]
[登録すると自動でURLが生成される]
[一般ユーザー用のrubyメソッド一覧画面 http://localhost:3000/user_ruby_methods
]
[管理者(私)が登録したメソッドに対し、ユーザーが説明を入れるhttp://localhost:3000/user_ruby_methods/new
]
[リンクを踏むと公式に飛べる。ユーザーは正しい情報を確認しながらメソッドを覚えられる]
[クイズの設定画面 http://localhost:3000/ruby_quiz/new
先ほどユーザーが登録したメソッドをクイズで確かめることができる]
[ユーザーがクイズに答える画面http://localhost:3000/ruby_quiz/show
]
[「回答を見る」ボタンを押すと、このように前回の答えと、公式のリンクがあり、確かめることが出来る。 また、今回の内容の方が良かったら「内容を更新する」ボタンで更新できる。 また、「おぼえた!」ボタンを押すとおぼえた!に移動し、復習モードで復習できる。]
@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 | 退会処理 |
また、ユーザーがクイズするメソッドのデータは、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もほぼ問題なく設定できておりました🙇♂️ 本番環境で稼働後は、管理画面から微調整をする予定です🙇♂️
見直しありがとうございます。いくつかコメントします。
user_ruby_methods
テーブルの remembered
が更新される認識ですが、POSTまたはPUT用のURIは不要でしょうか?@yuuu
「一般ユーザー用メソッドの新規登録画面」のURIが漏れてそうです
こちらなのですが、新しいUIでは、クイズの中で登録を行うことになりました。
user_ruby_methods
テーブルのレコードが作成される(その際remembered
の値はボタンに応じて入る)memo
のカラムが更新される
クイズの画面で「知っている」「知らない」を選択することで、 user_ruby_methods テーブルの remembered が更新される認識ですが、POSTまたはPUT用のURIは不要でしょうか?
既存の POST | /user_ruby_methods | 一般ユーザー用メソッドの新規登録 |
---|---|---|
PATCH | /user_ruby_methods/id | 一般ユーザー用メソッドの更新 |
-- | -- | -- |
で対応出来るのかな、と思っているのですが、もし難しそうな場合は、 POSTまたはPUT用のURIを追加しようと思います🙇♂️
なるほど。クイズでは予めユーザーがリストアップしたメソッドのみが出題されるのかなと推測していましたが、このシステムに登録されている全メソッドのうち、そのユーザーがまだ覚えていないものが出題される認識で合っていますでしょうか?
なるほど。クイズでは予めユーザーがリストアップしたメソッドのみが出題されるのかなと推測していましたが、このシステムに登録されている全メソッドのうち、そのユーザーがまだ覚えていないものが出題される認識で合っていますでしょうか?
クイズに挑戦する条件なのですが、このような仕様を想定してます
のどちらかを選択してもらって、クイズに挑戦してもらう、という仕様になります🙇♂️
[メソッドに対する覚えたか覚えてないかを管理する、enumのデータ型]
[クイズ出題画面]
回答ありがとうございます 👍 納得しました。 このリソース設計で大丈夫そうですね!
ペーパープロトタイプ
https://bootcamp.fjord.jp/products/16181
リソース
最終的なリソース設計
過去のリソース
| 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 | 退会処理 |
説明
このアプリの主な機能は
methods
とquiz
です。methods
railsの
resources
を使ったRESTfulなapiで作ります。GET /methods
以外は、railsの標準的な機能で作るのですが、GET /methods
はreactを使って構築する予定です。 railsはデータベースから、ユーザーに紐づいたmethods
の全てを取得し、 reactにデータを渡し、reactはstateで状態管理します[
/methods
でreactが管理するデータ]※
vite_rails
を使って、railsからreactにデータを渡し、呼び出します検索の絞り込みは、reactで管理している値を利用し、リクエストを送らず描画します。
[
/methods
]quiz
クイズは、DB上ではリソースを持ちません。 最初にクイズの設定画面である
/quiz/new
にアクセスし、 ユーザーが設定を入力後、POST /quiz
にリクエストを送ります。 その値を利用し、methods
テーブルから言語に応じたメソッドを一つ取得し、をboolean(表示・非表示フラグ)で管理した値と合わせて、
GET /quiz
に渡します。[
/quiz/new
]次のクイズに行く際の説明
次のクイズに行く際は、こちらの写真の右下の「次の問題」というボタンをクリックすると、次のクイズが出題されます。 [
/quiz
]次のクイズを出題するために、
のような値も合わせて、
POST /quiz
にリクエスト送ります。 この値を利用して、先ほど説明した処理を行います。ちなみに、URLから
GET /quiz
を直打ちした場合は、デフォルトでremembered
がfalseであるメソッドからランダムで取ってきて、そのメソッド +を
GET /quiz
に渡し、クイズを作成します。GET /quiz
はreactで作成します。 管理するデータは以下です[
/quiz
でreactが管理するデータ]この値を利用し、
remembered
がfalseであるメソッドを、保有しているlanguage
からランダムで取ってくるというのを繰り返します