Torihaji's Growth Diary

Little by little, no hurry.

初めての個人開発日記 2日目

はじめに

おはようございます torihaziです

現在、朝の7時24分です。

リリースまであと1週間ちょいしかないので実務と並行してやるしかありません

今日はテーブル構造とDocker立ち上げ、認証までをやりたいと思います

途中で技術選定も入れていきます。

技術選定

ここに追加していく感じです

  • frontend
    • Nextjs
  • backend

ディレクトリ構成

このプロジェクトのディレクトリ構成についてです

top/
├─ table/ 
│  ├─ Dockerfile
│  ├─ table.pdf
├─ back/
│  ├─ rails_project/
├─ front/
│  ├─ nextjs_project/

このtable、back、frontをgit管理していこうと思います。

テーブル構造

ER図を書くためにこちらを使います。

理由は手間が少ないから。よくあるツールだとパワーポイントみたいな感じで

四角形選択して、大きさ調整して、クリックして文字入力して、、、

という感じで面倒なので。

んじゃ書き始める

詰まったとこ

こんな感じで詰まったとこをメモ程度に書き残します。

これ使わないとだらだら続いてみづらいためです。

1つ目

カラムの属性でstringは1~255文字、textは1~むっちゃ長い文字。

2つ目

タグはどういうふうにテーブル管理するか。

diary(日記)は0個以上のタグを持ちうるし、タグもまたそう。

ということで中間テーブル使うのが良さそう。

https://zenn.dev/kibe/articles/0f3cc25bac273a

3つ目

外部キー制約について

よくある親が削除されたらその子のレコードも削除したいときに設定する

dependent: :destroy。

これについては DBに対して直接設定する ON DELETE CASCADEという方法もあるらしい。

前者はコールバックを設定できるらしいが、後者は無理らしい。

てことで慣れてる前者で。方法があるだけ知っておこう。

dependent: :destroy:

Railsアプリケーションを通じての操作時のみ動作します。
モデルのコールバックが実行されます。
関連するレコードの削除をより細かく制御できます。

ON DELETE CASCADE:

データベース直接操作時にも動作します。
パフォーマンスが若干良いです。
コールバックは実行されません。

一応できた。けどあれだ。あっているのかわからない。

まぁいいか。Claudeに助言求めたけど概ねいいらしいし、下記の要件は満足してると思う。

  • ログイン、新規登録 (railsのdevise使う予定)
  • 日記に付与するタグ
  • 日記のCRUD

ということでできました。

GitHub - torihazi/diary_table

開発環境構築

Dockerで作ります。

これを参考にしながら。

Rails 7 x React 18(Javascript) x Docker 環境構築 #JavaScript - Qiita

.
├── back
│   ├── Dockerfile
│   ├── Gemfile
│   ├── Gemfile.lock
│   ├── entorypoint.sh
│   └── 作業ディレクトリ
├── front
│   └── 作業ディレクトリ
└── docker-compose.yml
└── .env

docker-compose.yml

version: "3"
services:
  db:
    image: postgres:latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      - POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      - POSTGRES_DB: app_development
    ports:
      - "5432:5432"
  back:
    build:
      context: ./back
      dockerfile: Dockerfile
    volumes:
      - type: bind
        source: ./back
        target: /app
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3001:3000"
    environment:
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      TZ: Asia/Tokyo
      RAILS_ENV: development
    depends_on:
      - db
volumes:
  postgres_data:

詰まりました。

これでdocker compose buildしたらいけるかな。

いかない。なんで。

services.db.environment.[0]: unexpected type map[string]interface {}

dbのとこのenvironmentがおかしいみたい。

書き方に2通りあるんですね。初めて知りました。

キーバリューかリスト形式か。 = なら リストで、:なら-がいらないらしい。

ymlの記法、勉強しないとダメですね。この前も言った気がしますが。

ということでリスト形式他で使ってなかったのでキーバリューにしました。

再度トライ。行けたみたいですね。新しい発見でした。

backend

まずはコマンド1発

docker compose run --rm back rails new . --api --force --no-deps --database=postgresql --skip-docker

Gemfile変わったので再ビルド

試しにdocker compose up してみます。

http://localhost:3001 を見ると。。。

白紙。

dockerのログには

 ActiveRecord::ConnectionNotEstablished (could not connect to server: No such file or directory
back-1   |      Is the server running locally and accepting
back-1   |      connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
back-1   | ):

何やらpostgreと繋げないらしい。調べるとdatabase.ymlのhostが問題らしい。

ということで見て編集

default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
ここから追記
  host: db

docker compose restartして見ると

とりあえず繋がりはしたそうです。

パスワードの設定です。password: <%= ENV['DATABASE_PASSWORD'] %>これをhostの下に追記

再度 docker compose restart。

接続するuserの設定です。 username: postgresをpasswordの下に追記

再度 docker compose restart

ようやく現れました。

ちょっと待って。経験則でこれら設定しなきゃいけないのは理解した。でもなんで。

まーあとで追求しよう。

あとはcorsだ。

詳しいやり方はさっきのqiitaを参照。

ということでbackendの環境構築終了。

frontend

これはnextjsをapprouterで入れるだけ。

ただUIコンポーネントライブラリは何にしよう。

実務ではshadcnを使っていますが、そうですね。

調べてランキングtopだったものでいいでしょう。

ということでmaterial uiに決定です。

ReactのおすすめUIコンポーネントライブラリ|Kinsta®

docker-compose.ymlがある階層で docker compose run --rm front bashして

・・・

とやろうかと思っていたんだけど。

frontendはdocker使わないことが一般的らしい。確かに実務でもそうだし。

ということでこれはローカルでやろう。

docker compose ymlがある階層に移動して npx create-next-app@latest frontとする。

(ここはなんかダサい。反省ポイント)

てことで

✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? …Yes
✔ Would you like to use Tailwind CSS? …No
✔ Would you like to use `src/` directory? … No 
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to customize the default import alias (@/*)? …Yes
✔ What import alias would you like configured? … @/*

ということで立ち上がったのでgit管理して先に進む。

終了。

https://github.com/torihazi/diary_front

https://github.com/torihazi/diary_back

これを元に開発を進めていく。

認証画面作成

approuterで開発を進めていくわけだが、今気づいた。

pages-routerと何が違うのか知らない。調べる。

かなり重い。切り替え。pages routerでやることにした。

この間 1.5時間。

これも反省ポイント。pages-routerもまだあまり知らないのにその上位互換?の

app-routerに手を出すべきでない。

画面はこんな感じ。

react-hook-formとzodを入れる必要がありそう。あとMUIだ。

まずMUI入れないと。

入れるのにも一苦労。

まずMUIをいれるのに

npm install @mui/material @emotion/react @emotion/styled

そこからnextjsに統合するのに

npm install @mui/material-nextjs @emotion/cache @emotion/server

これなのね。MUI nextjsってやって調べて出てきたのは後者だったから

それやったら全部いけるのかと思ってた。

Next.js integration - Material UI

ということで修正したのがこれ。

_document.tsx

import {
  DocumentHeadTags,
  DocumentHeadTagsProps,
  documentGetInitialProps,
} from "@mui/material-nextjs/v14-pagesRouter";

import {
  Html,
  Head,
  Main,
  NextScript,
  DocumentProps,
  DocumentContext,
} from "next/document";

export default function Document(props: DocumentProps & DocumentHeadTagsProps) {
  return (
    <Html lang="en">
      <Head>
        <DocumentHeadTags {...props} />
      </Head>
      <body>
        <Main />
        <NextScript />
      </body>
    </Html>
  );
}

Document.getInitialProps = async (ctx: DocumentContext) => {
  const finalProps = await documentGetInitialProps(ctx);
  return finalProps;
};

_app.tsx

import "@/styles/globals.css";
import { AppCacheProvider } from "@mui/material-nextjs/v14-pagesRouter";
import type { AppProps } from "next/app";

export default function App({ Component, pageProps }: AppProps) {
  return (
    <AppCacheProvider>
      <Component {...pageProps} />
    </AppCacheProvider>
  );
}

ヘッダーってどう作ろう。

なんかsxで色々指定しないとcssいじれないのか。めんどくさいな。

sxは普通のcssか。かったるいな。

そう考えるとtailwindって楽だったのかな。

まぁいいや。慣れよう。

LPで苦戦してる。

コンポーネントいい名前見つからないから Claudeに考えてもらった。

<div>
    <HeroSection />    
    <FeaturesList />
    <DiaryPreview />
    <SignUpForm />
</div>

こんな感じ。

ダークモードにできるようにするのはあとでいいや。

最低限の見た目をぽくする。

これができたらログイン画面にいこう。

んー。めっちゃストレス。

確かにshadcnめっちゃ楽な気がする。tailwindでちゃちゃっとできるし。何より補完が効くから早い。

MUI、毎回sxって書いてやらなきゃいけないのだるいな。自分のやり方がおかしいのだろうか。

時間がかかる。

"機能だけは欲しいけど、見た目はこっちでいじらせて"ていうニーズがわかった気がしなくもない。

次は絶対shadcnでやろう。cssの設定がだるすぎる。慣れてないからか?

レスポンシブのやつが長い。fontSize: {md: OO, xl: OO}なんとかってやらないとダメ。

tailwindなら OO xl:OOって設定するだけでいいのに。

とりあえず慣れてきた。frontはモックでやってる。

現状。

NextjsのリンクとMUIのリンクを使うときに詰まったが、これで解決

Next.js 13でMUIのLinkを使う

めっちゃ進捗悪い。

今までできていたと思っていたのは他人が作った抽象化されたコンポーネントを使い回して

書いていたからだ。多分今の実力は元々こんなもん。知らんけど。

テキスト入力するとき毎回Typography書かないといけないのめんどい。

componentにspanとかpとか設定して分けられるにしても。

自分はdivとかpとかspanのclassNameにtailwind書いて行った方が早いと思うんだけど。

デザインで詰まったとこ。css

                <Typography
                  component="p"
                  sx={{
                    overflow: "hidden",
                    display: "-webkit-box",
                    WebkitLineClamp: 2,
                    WebkitBoxOrient: "vertical",
                    textOverflow: "ellipsis",
                  }}
                >
                  {diary.content}
                </Typography>

tailwindだともっと短くかけた気がするんだが。

linecrampは使ったことあった。がwebkitとか添えないとダメらしい。

登録フォームまでやりたかったが、現状。今日はここまで。

終わりに

反省。進捗が悪かった。

敗因は色々。MUIのキャッチアップに時間がかかった。

集中が続かなかった。どう作ろうかで悩みすぎた。

app-routerいけると思ったけど、よくわからなかったのでpages-routerに切り替えるまで時間がかかった。

初手からダークモードの実装に入ろうとしてた。

自分が欲しているコンポーネントがMUIのどれに当たるかで探してたら時間がかかった。

ただcssの知識は上達はしていると思う。こうすればこうなる、ほらね、という流れが多くなってきているし

やれることが増えてきているのはいいことだと思う。

少し完璧主義になっているのだろうか。どうしても気になって先に進めない、というところが多かった。

というか認証のfrontもbackもやってないことに今気づいた。

明日やらないと。

ということで今日はここまで。