Open23

📚アバター作成

minaho wakitaminaho wakita

■ おつきあいノート

▽サービス概要

誕生日や贈り物、最後にあった日を振り返れるノート
 ※具体的内容は別途書く!

▽目的

webアプリ開発のポートフォリオにする

▽作成のルール

・細部にこだわること
・完成までにかけれる時間は2か月
・設計、pjt管理、フロント・バックエンド・DB・インフラ技術について習得すること
・ドキュメントを残すこと

minaho wakitaminaho wakita

使用技術(予定)

設計

  • インフラ構成図
  • 画面遷移図
  • ER図

PJT管理

  • Git Hub
  • notion

フロントエンド

  • React.js
  • Ajax ★
選定理由

最も標準的と感じたから

バックエンド

  • Ruby on Rails ★
選定理由

あまたのフレームワークから、募集数が多いこと、比較的扱いが安易なこと、web開発に向いていることを条件に

DB

  • MySQL

インフラ

  • Heroku ★
  • AWS ★
  • Docker ★
  • 認証系
選定理由

ドキュメントが多いこと、流行りの構成であること

minaho wakitaminaho wakita

サービス概要

誕生日や贈り物、最後にあった日を振り返れるノート

  1. Info
  2. Story
  3. Tips

Info

  • 人ごとに、基本情報やエピソードを記録できる機能
  • 名前や記録した情報から特定の個人を検索できる機能
  • 五十音順や出会った日、関係性によって並び替える機能

Story

  • カレンダー上からエピソードを確認できる機能

Tips

  • InfoやStoryで登録した情報を抽出して、会話のネタになりそうな記事やYouTubeをリコメンドする機能
  • InfoやStoryで登録した情報を抽出して、おすすめのプレゼントをリコメンドする機能
minaho wakitaminaho wakita

ワイヤーフレームとして

機能の同士の関連と画面遷移についてしっかり考えたらもう少し追記が必要そうね。。
あと記入項目を具体的に10個増やしてみるのとか、登録画面の図も追加したほうがよいね。


minaho wakitaminaho wakita

上記のようなレイアウトとかを考えたり、Railsの導入動画を見ている間に圧倒言う間に時間が過ぎていた。

改めて考えてみると、個人情報を書くのがめちゃめちゃ怖いので、とりあえず
人ごとに、基本情報を記録できる機能 に絞って実装してみようと考えている。

イメージとしては、トモダチコレクションみたいな
顔パーツ選択式メモアプリ を作ることだ。

輪郭、目、鼻、口、チーク、眉のパーツを準備して、それぞれのパーツを選択し、位置を調整し、ニックネームとともに保存できるようにしようと思っている。

minaho wakitaminaho wakita

ざっと考えたER図

  • Personに人の情報
  • FacePartに各パーツの写真URL
  • FacePartSetに人と顔パーツの対応
  • FacePartPositionに顔パーツの位置情報
    を格納しようと思っている。・
+--------------+       +---------------+       +--------------+       +------------------+
|   Person     |       |   FacePart    |       |  FacePartSet |       | FacePartPosition |
+--------------+       +---------------+       +--------------+       +------------------+
| id           |       | id            |       | id           |       | id               |
| name         |       | name          |       | person_id    |       | face_part_set_id |
+--------------+       | part_type_id  |       | contour_id   |       | face_part_id     |
                       +---------------+       | eyes_id      |       | x_position       |
                                              | nose_id      |       | y_position       |
                                              | mouth_id     |       +------------------+
                                              | cheeks_id    |
                                              | eyebrows_id  |
                                              +--------------+


minaho wakitaminaho wakita

Git

ローカルのGitリポジトリとGitHubリポジトリを紐付け

git remote add origin <GitHubリポジトリのURL>

変更をステージングする

git add .

変更をコミットする

git commit -m "Commit message"

GitHubにpushする

git push -u origin main

minaho wakitaminaho wakita
  • rails プロジェクトの作成
    rails new friends_ --api --database=postgresql

  • gemファイルが見つからないエラー発生

An error occurred while installing pg (1.5.6), and Bundler cannot continue.

In Gemfile:
  pg
         run  bundle binstubs bundler
Could not find gem 'pg (~> 1.1)' in locally installed gems.
  • gemをインストール
    gem install pg
  • PostgreSQL クライアント ライブラリが見つかりません。エラー
Unable to find PostgreSQL client library.

Please install libpq or postgresql client package like so:
  ridk exec sh -c "pacman -S ${MINGW_PACKAGE_PREFIX}-postgresql"
  • おまじない
     MSYS2/MinGW環境の pacman を使用してPostgreSQLのクライアントライブラリをインストールするため
    ridk exec sh -c "pacman -S ${MINGW_PACKAGE_PREFIX}-postgresql"
  • 再度gemをインストール
    gem install pg
minaho wakitaminaho wakita

DB作成

Postgreのデータベースを作成するの忘れて沼田↓参考
https://qiita.com/Rairu_blog/items/d51795b350a2d1845308

テーブル作成


person_idとface_part_set_idに外部キー制約を持たせてDBテーブルを作成した。

rails g model FacePart name:string part_type:string url:string

DB
rails db:migrate

minaho wakitaminaho wakita

Rails console

rails console

  • FacePartモデルのレコードを全て取得する場合:
    FacePart.all

  • FacePartモデルの最初のレコードを取得する場合
    FacePart.first

  • FacePartモデルの特定の条件を満たすレコードを取得する場合(例えば、nameが"eyes"のレコードを取得する場合):
    FacePart.find_by(name: "eyes")

  • データベース内のテーブル一覧を取得
    ActiveRecord::Base.connection.tables

  • FacePartテーブルのスキーマ情報を取得する場合
    ActiveRecord::Base.connection.columns(:face_parts).map(&:name)

  • FacePartモデルのカラムを確認する場合
    FacePart.columns.map(&:name)

  • FacePartモデルのカラムを確認する場合
    FacePart.column_names

minaho wakitaminaho wakita

以下4つのAPIを作成していく。

・初期画面表示
 ①パーツ選択画面 全パーツのURL渡すAPI
 ②アバター画面 デフォルトのデータ渡すAPI
・登録処理
 ③name,パーツデータの登録 受け取り型API
・個別画面表示
 ④特定nameのパーツデータ渡すAPI

minaho wakitaminaho wakita

①パーツ選択画面 全パーツのURL渡すAPI

Railsの復習兼ねて 丁寧に

  • Controllerの作成
rails g controller Parts
class PartsController < ApplicationController

    # 全パーツのデータを渡す(/parts)
    def index
        @parts = Part.all
        render json: @parts.as_json(only: [:id, :part_type, :url])
    end
end
  • ルーティングの設定
     config/routes.rbに以下を追加
get 'parts', to: 'parts#index'
minaho wakitaminaho wakita

②アバター画面 デフォルトのデータ渡すAPI

  • Part テーブルにデフォルトデータかを判別するフラグを追加
  1. migrationファイル作成
rails generate migration AddDefaultFlagToParts default_flag:boolean
class AddDefaultFlagToParts < ActiveRecord::Migration[6.0]
  def change
    add_column :parts, :default_flag, :boolean, default: false
  end
end
rails db:migrate

!作成済みのレコードにもdefaultフラグfalseが追加されていた

  1. 各パーツ1レコードずつ、defalutフラグをtrueに変更した
# rails console
Part.find(1).update(default_flag: true)
  • Controller追記
class PartsController < ApplicationController

    # 全パーツのデータを渡す(/parts)
・・・

    # デフォルトのパーツのデータを渡す(/default_parts)
    def default_index
        @parts = Part.where(default_flag: true)
        render json: @parts.as_json(only: [:id, :part_type, :url])
    end
end
  • routing設定
get 'default_parts', to: 'parts#default_index'
minaho wakitaminaho wakita

③名前,パーツデータの登録 受け取り型API

初めに、、わかっていない部分

  • トランジション
  • ルーティングのところ

コントローラの作成

  • ポイントは、module APIやV1でAPIのバージョン管理をしていること
  • 同時に2つのテーブルに登録をかけるので、トランザクションを利用していること
  • create! のほうを使っていること
# app\controllers\api\v1\registration_controller.rb
module Api
    module V1
        class RegistrationController < ApplicationController
            def register_user_with_part_set
                ActiveRecord::Base.transaction do
                    user = User.create!(user_params)
                    part_set = user.part_sets.create!(part_set_params)
                    render json: {user: user,part_set: part_set}, status: :created
                end
            rescue ActiveRecord::RecordInvalid => e
                render json: {error: e.message}, status: :unprocessably_entity
            end
        
            private

            def user_params
                params.require(:user).permit(:name)
            end

            def part_set_params
                params.require(:part_set).permit(:part_id, :x_position, :y_position)
            end
        end
    end
end

ルーティングの設定

  • ポイントはよくわからないnamespaceを使っていること
# config\routes.rb
namespace :api do
    namespace :v1 do
      post 'register_user_with_part_set', to: 'registration#register_user_with_part_set'
    end
  end

テスト

以下のファイルを実行した

RubyのHTTPクライアントライブラリを使用してAPIを呼び出す方法があります。以下は、Rubyの標準ライブラリであるNet::HTTPを使用する例です。

# test_api.rb
require 'net/http'
require 'json'

uri = URI('http://localhost:3000/api/v1/register_user_with_part_set')
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri)
request['Content-Type'] = 'application/json'
request.body = {
  user: {
    name: 'John Doe'
  },
  part_set: {
    part_id: 1,
    x_position: 10,
    y_position: 20
  }
}.to_json

response = http.request(request)

puts response.code
puts response.body
ruby test\test_api.rb
minaho wakitaminaho wakita

特定nameのパーツデータ渡すAPI

  • コントローラの作成
class PartSetsController < ApplicationController

    # 特定のnameのPartSetのデータをすべて渡すAPI
    def index
        user = User.find_by(name: params[:name])
        if user
            part_sets = user.part_sets
            render json: part_sets.as_json(only: [:part_id, :x_position, :y_position])
        else
            render json: {error: "User not found"}, status: :not_found
        end
    end
end
  • ルーティングの設定
  get 'users/:name/part_sets', to: 'part_sets#index'
minaho wakitaminaho wakita

Next.js

Nest.jsとは

プロジェクトの作成

  • Node.jsのインストール
  • Next.jsのインストール
npm install next react react-dom
  • Next.jsプロジェクトの作成
npx create-next-app プロジェクト名
  • プロジェクトの実行
cd プロジェクト名
npm run dev
minaho wakitaminaho wakita

画面遷移

画面については3画面用意する。

  1. 一覧画面 (index.js)
    アバターの名前とプレビュー図の一覧を表示する
  2. 編集画面 (edit/[id].js)
    プレビュー画面とパーツ選択画面、保存ボタンを表示する
  3. 個別閲覧画面 (view/[id].js)
    プレビュー画面と編集ボタン、png出力ボタンを表示する
minaho wakitaminaho wakita

編集画面

http://localhost:3000/edit/[id]
例)http://localhost:3000/edit/1

利用ライブラリについて

  • useRouter Next.js フレームワークで提供されているフックの一つです。Next.js は、Reactベースのサーバーサイドレンダリングやルーティング機能を提供するフレームワーク
  • useState 関数コンポーネント内で状態を管理するために使用される。
  • AvatarEditor ユーザーのプロフィール写真などのアバターを編集するためのReactコンポーネント
minaho wakitaminaho wakita

useRouter よくある使い方

ルートのパス名を取得する

import { useRouter } from 'next/router';

function MyComponent() {
  const router = useRouter();
  const currentPath = router.pathname;

  return <p>Current path: {currentPath}</p>;
}

クエリパラメータを取得する

import { useRouter } from 'next/router';

function MyComponent() {
  const router = useRouter();
  const query = router.query;

  return <p>Query parameter: {query.param}</p>;
}

ページ遷移をおこなう

import { useRouter } from 'next/router';

function MyComponent() {
  const router = useRouter();

  function handleClick() {
    router.push('/another-page');
  }

  return <button onClick={handleClick}>Go to another page</button>;
}

動的なルートパラメータを取得する

import { useRouter } from 'next/router';

function MyComponent() {
  const router = useRouter();
  const { id } = router.query; //router.query オブジェクトから id プロパティの値を取り出し、それを id という変数に代入

  return <p>Dynamic parameter: {id}</p>;
}
minaho wakitaminaho wakita

useState よくある使い方

単一状態の管理

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // 初期値0のcount状態を宣言

  return (
    <div>
      <p>Count: {count}</p> {/* countの値を表示 */}
      <button onClick={() => setCount(count + 1)}>Increment</button> {/* ボタンがクリックされた時にcountを1増やす */}
    </div>
  );
}

複数の状態の管理

import React, { useState } from 'react';

function Form() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  return (
    <form>
      <input 
        type="text" 
        value={username} 
        onChange={(e) => setUsername(e.target.value)} 
        placeholder="Username" 
      />
      <input 
        type="password" 
        value={password} 
        onChange={(e) => setPassword(e.target.value)} 
        placeholder="Password" 
      />
    </form>
  );
}

状態の更新

const [count, setCount] = useState(0); // count状態を宣言

// count状態を更新する
setCount(count + 1);

前の状態を利用して更新

const [count, setCount] = useState(0); // count状態を宣言

// 前の状態を利用してcountを更新する
setCount(prevCount => prevCount + 1);

状態の初期化

const [count, setCount] = useState(() => {
  const initialCount = someExpensiveComputation(); // 何らかの計算結果を取得
  return initialCount;
});
  • コンポーネントが初めてレンダリングされる際にのみ実行される ※APIから値取得する際に重宝
  • 結果が初期状態として設定される
minaho wakitaminaho wakita

AvatarEditor

ユーザーのプロフィール写真などのアバターを編集するためのReactコンポーネント
ユーザーが画像をアップロードし、必要に応じてサイズを調整したり、切り抜いたりするためのツール

主な機能

  • ユーザーが画像をアップロードする機能
  • 画像をリサイズ・回転する機能
  • 画像を切り抜く機能
  • 切り抜いた画像をプレビューする機能
  • 編集された画像をサーバーに送信して保存する機能