Git Product home page Git Product logo

run_manage_spa's Introduction

README

ステータスコードとレスポンスボディの方針

200番台

  • POST
    • ステータスコード:201
    • シンボル:created
    • レスポンスボディ:新規データ
  • PUTおよびPATCH
    • ステータスコード:200
    • シンボル:ok
    • レスポンスボディ:更新後のデータ
  • DELETE
    • ステータスコード:204
    • シンボル:no_content

400番台

  • 401 :unauthorized あなたが誰だかわからないよ
  • 403 :forbidden あなたにこの操作は許可されてないよ

run_manage_spa's People

Contributors

fumiya-matsumoto avatar

Watchers

 avatar

run_manage_spa's Issues

メッセージ表示機能を実装

useToast()を使って、以下を実装する

  • ログイン
    • 成功時に「ログインしました」というメッセージを表示
    • 失敗時に「ログインできません」というメッセージを表示(本当はエラーを表示したい)
  • 新規登録
    • 成功時に「新規登録しました」というメッセージを表示
    • 失敗時に「新規登録できません」というメッセージを表示(本当はエラーを表示したい)
  • ログアウト
    • 成功時に「ログアウトしました」というメッセージを表示
    • 失敗時に「ログアウトできません」といういメッセージを表示(本当はエラーを表示したい)

API設計【BestTimeモデル】

概要

BestTimeモデルのAPIを設計する

目的

  • ユーザーが自身のbestを記録できるようにし、モチベーション増加に繋げる
  • ゆくゆくの機能追加のため(ユーザー分類等)

現状

なんだか無駄が多い気がする
best_time

改善版

こちらの方がスッキリしている
best_time_re

APIのエンドポイント設計

アプリケーションの画面とその遷移図

image

必要なAPI

  • ユーザー登録
  • ログイン
  • 自分の情報の取得
    • マイページとユーザー情報で表示するデータが異なるが、同じURIにするか異なるURIにするか...
  • 自分の情報の更新
  • ユーザー情報の取得
  • ユーザーの検索
  • 友達の追加
  • 友達の削除
  • 友達一覧の取得
  • 友達の検索
  • 友達の練習の一覧
  • 特定のユーザーの練習の一覧
  • 練習の投稿
  • 練習の編集
  • 練習の削除

テストを実装する

概要

APIのためのテストコードを書く

  • HTTPのレスポンスのステータスコードとレスポンスボディが適切に返されるかをテスト
  • rspecを使用しrspec/requests/ディレクトリ下にテストを作成する

目的

  • コードがうまく動くかを楽に検証するため
  • Railsやライブラリをアップデートした際の検証のため
  • 不具合の起こる可能性を減らすため
  • 自身のスキルアップのため

使用技術

rspec

テストコードの対象になるコード

  • 信頼できないところ
  • セキュリティ上、重要なところ
  • 不具合があると致命的なところ
  • 重要度の高いユースケース
  • 複雑なロジックやトリッキーなコード
  • 自動化した方が明らかに効率が良いところ

参考

投稿カードコンポーネントの作成

投稿カードのコンポーネントを作成する

イメージ

image

CSS

/* practice_post */

box-sizing: border-box;

position: relative;
width: 330px;
height: 399px;

background: #FFFFFF;
border: 1px solid #0BBBD7;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
border-radius: 10px 10px 0px 0px;


/* footer_area */

position: absolute;
width: 330px;
height: 35px;
left: 0px;
top: 365px;



/* footer_box */

box-sizing: border-box;

position: absolute;
width: 330px;
height: 35px;
left: 0px;
top: 365px;

border-top: 1px solid #C4C4C4;


/* like_icon */

position: absolute;
left: 3.94%;
right: 90.61%;
top: 93.73%;
bottom: 2.51%;

border: 1.66667px solid #808080;


/* comment_icon */

position: absolute;
left: 12.73%;
right: 81.82%;
top: 93.48%;
bottom: 2.51%;

background: #808080;


/* dm_icon */

position: absolute;
left: 21.52%;
right: 73.64%;
top: 93.48%;
bottom: 2.51%;

border: 1.25px solid #808080;


/* save_icon */

position: absolute;
left: 91.21%;
right: 4.55%;
top: 93.48%;
bottom: 2.26%;

background: #808080;


/* thoughts_area */

position: absolute;
width: 331px;
height: 125px;
left: 0px;
top: 240px;



/* thoughts_box */

position: absolute;
width: 331px;
height: 125px;
left: 0px;
top: 240px;



/* content */

position: absolute;
width: 300px;
height: 105px;
left: 15px;
top: 250px;

font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 20px;
/* or 167% */

color: #000000;



/* strength_area */

position: absolute;
width: 330px;
height: 40px;
left: 0px;
top: 200px;



/* strength_box */

box-sizing: border-box;

position: absolute;
width: 330px;
height: 40px;
left: 0px;
top: 200px;

background: #FFFFFF;
border-width: 1px 0px;
border-style: solid;
border-color: #C4C4C4;


/* strength_icon */

position: absolute;
width: 165px;
height: 40px;
left: 0px;
top: 200px;



/* strength_vacant_unit */

position: absolute;
left: 34.55%;
right: 55.76%;
top: 30%;
bottom: 30%;

background: #0BBBD7;


/* strength_vacant_unit */

position: absolute;
left: 46.67%;
right: 43.64%;
top: 30%;
bottom: 30%;

background: #0BBBD7;


/* strength_unit */

position: absolute;
left: 58.79%;
right: 31.52%;
top: 30%;
bottom: 30%;

background: #0BBBD7;


/* strength_unit */

position: absolute;
left: 70.91%;
right: 19.39%;
top: 30%;
bottom: 30%;

background: #D9D9D9;


/* strength_unit */

position: absolute;
left: 83.03%;
right: 7.27%;
top: 30%;
bottom: 30%;

background: #D9D9D9;


/* strength_box */

position: absolute;
left: 0%;
right: 0%;
top: 0%;
bottom: 0%;



/* strength_label */

position: absolute;
left: 12.73%;
right: 69.09%;
top: 22.5%;
bottom: 22.5%;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 14px;
line-height: 17px;
display: flex;
align-items: center;

color: #808080;



/* weather_place_area */

position: absolute;
width: 330px;
height: 40px;
left: 0px;
top: 160px;



/* weather_place_box */

box-sizing: border-box;

position: absolute;
width: 330px;
height: 40px;
left: 0px;
top: 160px;

background: #FFFFFF;
border-top: 1px solid #C4C4C4;


/* place_area */

position: absolute;
width: 165px;
height: 40px;
left: 165px;
top: 160px;



/* place_label */

position: absolute;
left: 12.73%;
right: 69.09%;
top: 22.5%;
bottom: 22.5%;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 14px;
line-height: 17px;
display: flex;
align-items: center;

color: #808080;



/* place_box */

position: absolute;
left: 0%;
right: 0%;
top: 0%;
bottom: 0%;



/* place_icon */

position: absolute;
left: 33.94%;
right: 50.91%;
top: 20%;
bottom: 25%;



/* Vector */

position: absolute;
left: 0%;
right: 0%;
top: 25%;
bottom: 0%;

background: #0BBBD7;


/* wether_area */

position: absolute;
width: 165px;
height: 40px;
left: 0px;
top: 160px;



/* weather_box */

position: absolute;
left: 0%;
right: 0%;
top: 0%;
bottom: 0%;



/* weather_label */

position: absolute;
left: 12.73%;
right: 69.09%;
top: 22.5%;
bottom: 22.5%;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 14px;
line-height: 17px;
display: flex;
align-items: center;

color: #808080;



/* weather_icon */

position: absolute;
left: 33.33%;
right: 52.12%;
top: 20%;
bottom: 20%;



/* Vector */

position: absolute;
left: 8.33%;
right: 8.33%;
top: 8.33%;
bottom: 8.33%;

background: #0BBBD7;


/* distance_time_area */

position: absolute;
width: 300px;
height: 80px;
left: 16px;
top: 64px;



/* distance_time_box */

position: absolute;
width: 300px;
height: 80px;
left: 16px;
top: 64px;

background: #0BBBD7;
border-radius: 10px;


/* distance_place_label */

position: absolute;
width: 78px;
height: 18px;
left: 27px;
top: 77px;

font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 15px;
display: flex;
align-items: center;

color: #FFFFFF;



/* distance_area */

position: absolute;
width: 65px;
height: 21px;
left: 27px;
top: 113px;



/* distance */

position: absolute;
width: 46px;
height: 17px;
left: 27px;
top: 113px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 24px;
line-height: 29px;
display: flex;
align-items: center;

color: #FFFFFF;



/* distance_unit */

position: absolute;
width: 19px;
height: 17px;
left: 73px;
top: 117px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 12px;
line-height: 15px;
display: flex;
align-items: center;

color: #FFFFFF;



/* time_area */

position: absolute;
width: 59px;
height: 38px;
left: 162px;
top: 95px;



/* time */

position: absolute;
width: 56px;
height: 18px;
left: 165px;
top: 115px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 19px;
display: flex;
align-items: center;

color: #FFFFFF;



/* time_label */

position: absolute;
width: 30px;
height: 18px;
left: 162px;
top: 95px;

font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 15px;
display: flex;
align-items: center;
text-align: center;

color: #FFFFFF;



/* pace_area */

position: absolute;
width: 56px;
height: 38px;
left: 242px;
top: 95px;



/* pace_time */

position: absolute;
width: 56px;
height: 18px;
left: 242px;
top: 115px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 19px;
display: flex;
align-items: center;

color: #FFFFFF;



/* pace_label */

position: absolute;
width: 39px;
height: 18px;
left: 242px;
top: 95px;

font-family: 'Inter';
font-style: normal;
font-weight: 400;
font-size: 12px;
line-height: 15px;
display: flex;
align-items: center;
text-align: center;

color: #FFFFFF;



/* header */

position: absolute;
width: 330px;
height: 50px;
left: 0px;
top: 0px;



/* header_box */

position: absolute;
width: 329px;
height: 50px;
left: 0px;
top: 0px;

background: #0BBBD7;


/* user_icon */

position: absolute;
width: 35.89px;
height: 36px;
left: 12.96px;
top: 7px;



/* Ellipse 3 */

position: absolute;
width: 35.89px;
height: 36px;
left: 12.96px;
top: 7px;

background: #FFFFFF;


/* Vector */

position: absolute;
left: 4.23%;
right: 85.5%;
top: 2.01%;
bottom: 89.47%;

background: #0BBBD7;


/* date */

position: absolute;
width: 181.45px;
height: 19px;
left: 75.77px;
top: 16px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 16px;
line-height: 19px;
display: flex;
align-items: center;
text-align: center;

color: #FFFFFF;

/* detail_button */

position: absolute;
width: 48.85px;
height: 18px;
left: 281.15px;
top: 8px;

font-family: 'Inter';
font-style: normal;
font-weight: 700;
font-size: 24px;
line-height: 29px;
display: flex;
align-items: center;
text-align: center;

color: #FFFFFF;


フォロー・フォロワー機能

概要

フォロー・フォロワー機能を実装する。

目的

  • フォロー・フォロワー機能を実装してユーザー間のソーシャルなコミュニケーションを可能にする
    • 多対多の関係になる
    • userテーブル同士の関係

目的達成のために

  • モデルを作成する
    • relationshipモデルを作成する
      • id
      • follower_id:reference
      • followed_id:reference
  • User/Relationshipの関連付け
    • active_relationships:能動的関係(フォローしているがフォローされてない)

参考

フロントエンドの設計

概要

フロントエンドを設計する。フロントエンドはReactを使って作る

目的

  • 保守性の低いフロントエンドにならないよう、設計をきちんと行う

メモ

Container/Presentational Componentについて

  • Container Component
    • データを扱うコンポーネント
    • データをもち、また親コンポーネントとして複数の子コンポーネントにデータを渡す役割を担当
  • Presentational Component
    • 受け取ったデータを表示するだけ
    • 例えば、ボタンやモーダルなど

二つを分けるメリット

  • 子コンポーネントの再現性を高める
    • Presentational Componentは子コンポーネントとしてUIを提供することだけに関心を持つ
    • そのため、どのようなデータが入ってくるか?によってその振る舞いを変えることができる
    • もし子コンポーネントにデータを持たせてしまうと、複数ページで同じようなUIなのにデータが異なるという場合に再利用できず、結局コピペするということになってしまう

本アプリケーションのコンポーネント設計

Container層/Component層をディレクトリから分ける。1ページ1Containerとする。

Container層

一旦、以下の4つを作る。ゆくゆくはTeam.jsxなどを作っていきたい。
これらは各ページの最も上部に存在するContainer層で、データを扱う。
中身のボタンやモーダル等は小コンポーネントがレイアウトのみ提供する。

  • containers/PracticePosts.jsx
  • containers/Calender.jsx
  • containers/Feeds.jsx
  • containers/MyPage.jsx

Component層

  • components/Buttons/HogeButton.jsx
  • components/Modals/FugaModel.jsx
  • components/Wrapper.jsx

APIを呼ぶ関数

フロントエンドからAPIを叩く部分を考える。一般的にファイルごとに関心を分離するらしい。
そのため、Reactのコンポーネントはあくまでレイアウトやデータを保持することを担当させる。
その場合に、各種APIを呼ぶ部分を関数化して他のファイルに分けることで関心を分離することができる。

コンポーネントファイルの中にAPIを叩く関数を定義してしまうと、他のページから同じAPIを叩きたい場合にコピペするハメになるため、コンポーネントファイル/API関数ファイルを分ける。

  • apis/users.js
  • apis/posts.js
  • apis/best_records.js
    これらのファイルの中にはただのJavaScriptの関数だけが存在する。

reducer

Reactの組み込みAPIであるReact Hooksを使う。

  • reducers/users.js
  • reducers/posts.js
  • reducers/best_records.js

URLの管理

APIのURL管理も別ファイルに分ける。RailsでURLがroutes.rbにまとまっているように、フロントエンドでも「ここを参照すればURLがわかる」という状態を明確にする。
urls/index.jsを作成して、ここにAPIのURL文字列を定義していく。

API設計【Userモデル】

概要

UserモデルのAPIを設計する

  • Web API:The Good Partsを参考に「美しい設計のAPI」を作る

目的

  • 美しいWeb APIには以下の利点がある
    • 使いやすい
    • 変更しやすい
    • 頑丈である
    • 恥ずかしくない

目的達成のために

  • 以下の原則に従う
    • 仕様が決まっているものに関しては仕様に従う
    • 仕様が存在していないものに関しては、デファクトスタンダードに従う

参考

API設計【Postモデル】

概要

PostモデルのAPIを設計する

  • Web API:The Good Partsを参考に「美しい設計のAPI」を作る

目的

  • 美しいWeb APIには以下の利点がある
    • 使いやすい
    • 変更しやすい
    • 頑丈である
    • 恥ずかしくない

目的達成のために

  • 以下の原則に従う
    • 仕様が決まっているものに関しては仕様に従う
    • 仕様が存在していないものに関しては、デファクトスタンダードに従う

参考

Postモデルのカラムを最小限にして、演算できる値はpost.rbで関数定義する

概要

Postモデルについて、演算処理できる値のカラムが存在するため、DBから消し、post.rbに演算関数を定義する。

目的

演算的に求まる値は整合性観点から持たせない方が望ましいため。

タスク

  • Postモデルから演算処理できる値のカラムを削除する
  • Model側に関数を記述(例:distanceとtimeからpaceを算出)

将来的な検討事項

  • アダプター層、サービス層の導入
    • Model側に処理が増えると、責務が集中し本質的でないコードが増える(Modelがファットになる)
    • 変換処理を担当するアダプター層、サービス層などを導入し、レイヤーの責務を明確にする
    • Rails:サービス層の導入
  • RDBMSのViewを導入
  • ビューとはテーブルから取得したいデータの条件を定義してあたかも独立したテーブルのように扱えるようにしたもの。
  • ビューそのものはデータを持たず、元となったテーブルからデータを参照する。
  • 例えばテーブルの一部のカラムだけを取り出したビューを作成し、他のユーザーにはビューだけを閲覧できるように権限を設定するといった利用ができる
  • DBのビューを使ってみたらRailsのコード修正が(ほぼ)要らなくなった話
  • ビューの作成
  • OLTP、OLAPを理解する
  • ユーザーリクエストを受け付けるアプリケーションとは別に、ジョブを実行し正しい値に戻すことを行います

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.