rails(APIモード) + react(typescript) + mysql(docker) で rails の雛形を作成し疎通確認まで行う

#目的
以下の構成でアプリケーションの雛形と疎通確認を行う
バックエンド：rails(APIモード)
フロント：React(typescript)
DB:MySQL(from docker)

#環境情報
##OSバージョン
macOS Catalina(10.15.4)

#1.MySQL の準備
ホストOS上に直接 install すると別アプリなどでDBを分けたりバージョンを変えたりするのが面倒そうなので docker で構築する
##前提
Docker(docker-compose) を install 済みであること
Docker(docker-compose) の install についてはこちら
https://docs.docker.com/docker-for-mac/install

##mysql-client の準備
###mysql-client を install する

```bash
brew install mysql-client
```

###環境変数を追加##

```bash
echo '' >> ~/.zprofile
echo '# mysql-client' >> ~/.zprofile
echo 'export PATH="/usr/local/opt/mysql-client/bin:$PATH"' >> ~/.zprofile
echo 'export PKG_CONFIG_PATH="/usr/local/opt/mysql-client/lib/pkgconfig"' >> ~/.zprofile

source ~/.zprofile
```

##MySQL(docker) の準備
###MySQL(docker) 用のディレクトリを作成

```bash
mkdir mysql-docker
cd ./mysql-docker

# データを永続化するためにデータ用のディレクトリを作成しておく
mkdir data
```

###docker-compose.ymlを作成

```yaml
version: '3'
services:
  mysql:
    image: mysql:5.7
    env_file:
      - .env
    volumes:
      - ./data:/var/lib/mysql
    ports:
      - 13306:3306
    tty: true
```

###.env を作成

```
MYSQL_ROOT_PASSWORD=mysql
TZ=Asia/Tokyo
BIND-ADDRESS=0.0.0.0
```

###MySQL(docker)を起動する

```bash
docker-compose up -d
```

##接続設定 & 接続確認
###/etc/hosts を編集する
ホストからコンテナの MySQL にアクセスする際に -h localhost ではアクセスできないため別名でアクセスするようにする
以下の様に 「mysql-server」を追記する

```bash
127.0.0.1       localhost mysql-server
```

###接続確認

```bash
mysql -P13306 -u root -h mysql-server -pmysql
```

#2.rails の準備
##前提
ruby & rails を install しておくこと 
ruby & rails の install についてはこちら
https://qiita.com/masatoshi_watanuki/private/fc2d8b4702e881a97768

## mysql2 install の準備
mysql2 の install 時に以下のエラーが発生してしまうため <b>bundle config ...</b> を実施しておく
参考：https://kuzugr.com/article/30

<b>mysql2 install 時の エラー</b>

```
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
```

<b>以下のコマンドを実行する</b>

```bash
bundle config --global build.mysql2 --with-opt-dir="$(brew --prefix openssl)"
```

##rails をapiモードで生成する

```bash
rails new sample_app -d mysql -T --api

cd sample_app
```

##DB の設定
config/database.yml を以下の様に変更する

```yaml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: mysql
  host: mysql-server
  port: 13306
```

DB を作成

```bash
rails db:create
```

##rack-cors を有効にする
Client(React) と Backend(Rails)は別オリジンとなるため rack-cors を使用して Client <=> Backend 間でアクセスできる様にする

Gemfile の以下の部分のコメントアウトを外す

```ruby
gem 'rack-cors'
```

```bash
bundle install
```

config/application.rb に以下を追加する

```ruby
config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins 'http://localhost:3000' # React の Origin
    resource '*', :headers => :any, :methods => [:get, :post, :put, :delete, :options], :expose => ['access-token']
  end
end
```

##起動確認
rails を起動する

```bash
rails s
```

以下にアクセスして確認する
http://localhost:3000/
![スクリーンショット 2020-03-14 14.26.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596550/2e2870e0-2cf7-f16f-d11a-097aa726581f.png)

#アプリに機能を追加する
商品(product)を登録・参照・削除できる機能を実装する

## product関連の Controller, Model 等を生成しテーブルを作成する
```bash
# ControllerやModel等を生成
rails generate scaffold product name:string price:integer comment:string

# DBにテーブルを作成
rails db:migrate
```

## 動作確認
```bash
rails c
# Productを登録
Product.create(name: '商品1', price: 50000, comment: 'コメント')
exit

rails s
``` 

以下のURLにアクセスしてJSONの配列が帰ってくればOK
http://localhost:3000/products

```
[{"id":1,"name":"商品1","price":50000,"comment":"コメント","created_at":"2020-04-04T02:53:20.406Z","updated_at":"2020-04-04T02:53:20.406Z"}]
```

#3.Reactの準備
##前提
nodejs & npm が install 済みであること
nodejs & npm の install についてはこちら
https://qiita.com/masatoshi_watanuki/items/b8eef771ab3e2ca3d525


## 雛形を作成する
任意のディレクトリで以下のコマンドを実行する

```bash
npx create-react-app sample-client --typescript
```

動作確認

```bash
cd sample-client

npm start
```

![スクリーンショット 2020-04-04 16.18.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596550/288dfe06-c5e4-3da5-b67e-bea135fd13b1.png)
※確認できたら CTRL + c で停止してOK

## API呼び出しを行うため axios を install する
```bash
npm install axios
```

##Rails からProductのデータを取得して表示できるようにする
src/App.tsx

```tsx
import React from 'react';
import './App.css';

import axios from 'axios';

const PRODUCTS_API_URL = 'http://localhost:3001/products';

class App extends React.Component<any, any> {
  constructor(props: any) {
    super(props)
    this.state = { products: [] }
  }

  // renderの中でsetStateすると再描画しようとしてrenderが呼ばれるため無限ループとなってしまう
  // componentDidMountではComponentがMountされたタイミングで実行されるため無限ループを回避できる
  componentDidMount() {
    axios
      .get(PRODUCTS_API_URL)
      .then((results) => {
        this.setState({ products: results.data });
      })
      .catch((error) => {
        alert(error);
      });
  }

  renderProducts() {
    return (
      <div>
        {this.state.products.map((v: any) => {
          return (
            <div>
              <p>name: {v.name}</p>
              <p>price: {v.price}</p>
              <p>comment: {v.comment}</p>
            </div>
          );
        })}
      </div>
    );
  }

  render() {
    return (
      <div className="App">
        <h1>-- Products --</h1>
        {this.renderProducts()}
      </div>
    );
  }
}

export default App;
```

## 動作確認
```bash
cd {Rails のROOTディレクトリ}

# デフォルトの3000ポートは React が使用するため3001で起動する
rails s -p 3001
```

```bash
cd {React のROOTディレクトリ}

npm start
```

ブラウザで http://localhost:3000 にアクセスする

![スクリーンショット 2020-04-05 15.43.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/596550/f16c340e-5b6c-5e3b-97e9-bdd3e408ff20.png)

（突っ込みどころは多々あると思うけど）疎通確認までできたため今回はここまで

<!--
## 以下は後回しにする

##yarn の install
こちらは手動で install する必要があるため下記コマンドにて install する

```bash
brew install yarn
```

##Gemfile を編集する
Gemfileを以下のインラインコメントの通り編集する

```ruby
# rspec-rails を追加する
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'rspec-rails'
end

```

##rspec を installする
Gemlock に 「rspec-rails」 を追加する

```bash
bundle install
rails generate rspec:install
```

## product に画像をアップロードできるようにする
##Gemfile を編集する
Gemfileを以下のインラインコメントの通り編集する

```ruby
# コメントアウトを外す
gem 'rack-cors'
# 以下の行を追加する
gem 'carrierwave'
```

### uploader を生成する
```
rails g uploader image
```

app/models/product.rb に以下の行を追加する

```ruby
mount_uploader :image, ImageUploader
```
-->