Ruby on Rails 7 + React を fly.io にデプロイした時のlog

個人開発を始めるにあたりローカルの開発を久々に作ったその時のlog
fly.ioにもデプロイできるようにして公開したくなったらできるように準備するところまでやります

色々直したいところはあるので気が向いたら修正する

### docker compose での開発環境作成

手元で動かして確認したいので docker compose で動くようにする

参考にした記事

https://zenn.dev/naoki0722/articles/272ef57c6dafba

ほとんど記事に記載されている通りrubyのバージョンとDBをpostgresqlに変更しています

下記のファイルを用意した
- Dockerfile
- compose.yaml
- entrypoint.sh
- Gemfile
- Gemfile.lock

Dockerfileを作成する

```Dockerfile
FROM ruby:3.2.2

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update \
  && curl -fsSL https://deb.nodesource.com/setup_14.x | bash \
  && apt-get install -y nodejs cron \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* \
  && mkdir /app-name

RUN npm install --global yarn
RUN yarn install --network-timeout 600000

WORKDIR /app-name
COPY Gemfile /app-name/Gemfile

COPY Gemfile.lock /app-name/Gemfile.lock

RUN bundle install

COPY . /app-name

COPY entrypoint.sh /usr/bin/

RUN chmod +x /usr/bin/entrypoint.sh

ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]
```

```entrypoint.sh
#!/bin/bash
set -e

rm -f /app-name/tmp/pids/server.pid

exec "$@"
```
docker-compose.yml を作成する

```compose.yaml
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    networks:
      - db-net
  web:
    build: .
    stdin_open: true
    command: /bin/sh -c "rm -f tmp/pids/server.pid && ./bin/dev"
    ports:
      - "3000:3000"
    depends_on:
      - db
    volumes:
      - .:/app-name
    networks:
      - web-net
      - db-net

networks:
  web-net: {}
  db-net: {}
```

```Gemfile
source "https://rubygems.org"

ruby "3.2.2"

gem "rails", "~> 7.0.4"

```

Gemfile.lock は空のファイル作成するだけ


ファイルが準備できたらビルドする

```bash
docker-compose build
```

rails new をします
記事を参考に`esbuild` を指定しています

```bash
docker-compose run web rails new . --database=postgresql -a propshaft --javascript=esbuild
```

ビルドが終わったら database.yml の接続情報を編集する

``` config/database.yml
development:
  <<: *default
  database: diy_pc_rooms_development
  host: db
  username: <%= ENV['POSTGRES_USER'] %>
  password: <%= ENV['POSTGRES_PASSWORD'] %>
```

とりあえずあげてみる

```bash
docker compose up
```
db がないと怒られるのでcreateする

```bash
docker compose run web rails db:create
```

ここまでで`http://0.0.0.0:3000/`にアクセスするとrailsの画面がでる

![0.0.0.0_3000_.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316631/44a750fa-1602-2d95-47ec-d306c5a95e22.png)



#### Reactを追加する

とりあえず "/" のパスを設定する

``` app/controllers/homes_controller.rb
class HomesController < ApplicationController
  def index
  end
end
```
```config/routes.rb
Rails.application.routes.draw do
  root 'homes#index'
end
```
``` app/views/homes/index.html.erb
<h1>Homes#index</h1>
<p>Find me in app/views/homes/index.html.erb</p>

```

ここまでで一旦表示できるか`/`にアクセスして確認しておく


reactとreact-domを追加する
```bash
docker-compose run --rm web yarn add react react-dom
```

参考にした記事のようにrails new時にエラーは発生しなかった
また`rails javascript:install:esbuild` が実行されているように見えたので特にコマンドは実行する必要がなかった
ただpackage.jsonにbuildコマンドの追加は必要なので下記の記述を追加する

```package.json
"scripts": {
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets"
}
```

これで下準備は終わりです

viewごとにReactをPropsを設定できるようにしていく
idとdataを使ってPropsを渡せるように`Mount.tsx`を追加する

```app/javascript/Mount.tsx
import React from 'react'
import { createRoot } from 'react-dom/client'

const Mount = (Component, mountNodeId) => {
  const mountNode = document.getElementById(mountNodeId)
  const props = JSON.parse(mountNode.getAttribute("data"))
  createRoot(mountNode).render(<Component {...props} />)
}

export default Mount
```

indexで表示する簡単なcomponentsを作成する

``` app/javascript/components/Hello.tsx
import React from 'react'

const Hello = ({ name }) => <h1>Hello, {name}!</h1>

export default Hello
```

``` app/views/homes/index.html.erb
<%= content_tag :div, id: "hello", data: {name: "kiitan"}.to_json do %><% end %>
```

`application.js`を`application.tsx`に拡張子を変更し下記の記述を追加する

```app/javascript/application.tsx
import Mount from './Mount'
import Hello from './components/Hello'

Mount(Hello, 'hello')
```

この状態で開発環境にアクセスすると *Hello, kiitan!* と表示されていればReactの表示ができています

### fly.ioにデプロイしてみる

ここまではローカルのdocker環境で開発を進めてきました
今回fly.ioを使ってみたかったのでデプロイしてみる
ドキュメントを眺めながらやった

https://fly.io/docs/rails/getting-started/

`fly`コマンドを入れる
brew で入れられるようなので自分はbrewで入れました

```bash
brew install flyctl
```

コマンドを打つとブラウザが開くのでログインできる

```
fly auth login
```

セットアップコマンドを実行する
アプリの名前やリージョンを聞かれるので選択していきます
今回は`Postgresql`をりようするのでこちらを作る選択だけしておきます

```bash
fly launch
```

デプロイコマンドを実行する

```bash
fly deploy
```

デプロイが完了したら `fly open` で開くことができます

今のままではRuby on Railsのhostのエラーが発生します
エラー画面に書いているようにhostsを `development.rb` に追加します

```config/environments/development.rb
config.hosts << "xxxx.fly.dev"
```

もう一度デプロイすると `The asset 'application.js' was not found in the load path.` が発生すると思います
これは`yarn build`のコマンドをローカル環境ではoremanの`Procfile.dev`にて実行するようになっていますがfly.ioでは実行されていないためです
そこで手っ取り早くDockerfileを修正してコマンドを走らせます

```diff
FROM ruby:3.2.2

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update \
  && curl -fsSL https://deb.nodesource.com/setup_14.x | bash \
  && apt-get install -y nodejs cron \
  && apt-get clean \
  && rm -rf /var/lib/apt/lists/* \
  && mkdir /app-name

WORKDIR /app-name

# ここを追加
+ COPY package.json /app-name/package.json
+ COPY yarn.lock /app-name/yarn.lock
+ RUN npm install --global yarn
+ RUN yarn install --frozen-lockfile --network-timeout 600000

COPY Gemfile /app-name/Gemfile

COPY Gemfile.lock /app-name/Gemfile.lock

RUN bundle install

COPY . /app-name

COPY entrypoint.sh /usr/bin/

RUN chmod +x /usr/bin/entrypoint.sh
RUN yarn build

ENTRYPOINT ["entrypoint.sh"]

EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]

```

修正後再度デプロイすれば問題なく表示できるようになっています
一旦画面が表示できたので満足

<!-- 
### rspec を導入する

rspecをinstallする

``` Gemfile
group :development, :test do
  gem "rspec-rails", "~> 6.0.1"
  gem "rspec-core", "~> 3.12.2"
  gem "rspec-expectations", "~> 3.12.2"
  gem "rspec-mocks", "~> 3.12.5"
  gem "rspec-support", "~> 3.12.0"
  gem "diff-lcs", "~> 1.5.0"
end
```

テスト環境用のDBを作成するするため接続情報を変更する

```config/database.yml
test:
  <<: *default
  database: diy_pc_rooms_test
  username: <%= ENV['POSTGRES_USER'] %>
  password: <%= ENV['POSTGRES_PASSWORD'] %>
```



関連ファイルを作成する

``` bash
docker compose run web bundle exec
```
-->