Dockerでrails7 + tailwind + daisyuiの環境構築をする

# はじめに
今回、webアプリ（ポートフォリオ）を作成するにあたり、Herokuでのデプロイに非常に苦労しました。理由はいくつかありますが、特にDockerを使用したtailwindとdaisyuiの環境構築がうまくいかなかったことが大きな要因です。（実際にはHerokuの前にFly.ioのデプロイも試みましたが、そちらでも成功できませんでした…）
そのため、ここではDockerを使ったrails+tailwind+daisyuiの環境構築について詳しく説明したいと思います。

私自身、まだまだ未熟な未経験エンジニアですので、誤った解釈をしている可能性もあります。もしそういった場合がありましたら、ぜひコメントでご指摘いただければ幸いです。

# 前提
- Docker version 20.10.23
- Ruby on Rails 7.0.4
- Ruby 3.1.2


# Dockerでの環境構築

[こちら](https://qiita.com/ICU1234/items/be0d4dfca7af2505d011)にも、書いていますので良ければチラッと見てみてください。
ただ、若干異なる部分があるのでこの記事にも記載しておきます。

## ファイルを作成
まずは、プロジェクトを配置するフォルダを準備します。ここが Rails のルートディレクトリになります。
今回はsample-appディレクトリを作成し、その下にDockerの環境構築をしていこうと思います。
以下を順にターミナルで叩いてください。(コードエディタで直接作成しても大丈夫です)
```
mkdir sample-app
cd sample-app
touch Dockerfile Gemfile Gemfile.lock docker-compose.yml entrypoint.sh
``` 

## それぞれのファイルに記述
それでは、先ほど作成したファイルにコードを記述していきましょう。

### Dockerfile
```
FROM ruby:3.1.2

ENV TZ Asia/Tokyo
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs && apt-get install -y vim

# Install yarn
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash - \
  && wget --quiet -O - /tmp/pubkey.gpg 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 -qq \
  && apt-get install -y nodejs yarn

# 作業ディレクトリを指定
WORKDIR /sample-app

# ホストのGemfileとGemfile.lockをコンテナにコピー
COPY Gemfile Gemfile.lock /sample-app/

# bundle installを実行
RUN bundle install

# ホストのカレントディレクトリをコンテナにコピー
COPY . /sample-app/

# entrypoint.shをコンテナ内の/usr/binにコピーし、実行権限を与える
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh

# ENTRYPOINTとCMDを統合
ENTRYPOINT ["entrypoint.sh"]
CMD ["rails", "server", "-b", "0.0.0.0"]
```
- sample-appと記載してありますが、おそらくなんでもいいです。私は余計なエラーを起こさないために、webアプリ名やルートディレクトリ名と同じにしています

- `curl -sL https://deb.nodesource.com/setup_18.x `で特定のバージョンのnodeをインストールすることができます。（後々、tailwindやdaisyuiを導入する時に必要ですので、nodeを入れるようにしてください）

### docker-compose.yml
```
version: '3'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: password
    volumes:
      - postgres_volume:/var/lib/postgresql/data
    ports:
      - '5432:5432'

  web:
    build:
      context: .
      dockerfile: Dockerfile
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/sample-app
    ports:
      - 3000:3000
    stdin_open: true
    tty: true
    depends_on:
      - db
volumes:
  postgres_volume:
```

- `db`以下は、dbコンテナの設定について記述しています
- `postgres_volume:/var/lib/postgresql/data`は、/dataまでpathを指定しないとdbの永続化できないです。また、永続化しないと`docker-compose down`するたびにdbを作成しないといけず非常に手間なのでここで永続化しておきます。
- `web`以下は、アプリ側の設定を記述しています
- `stdin_open: true`は、dockerコンテナを起動したままにできる。コンテナ内に入ってコマンドを打ち込めます
- `tty: true`は、コンテナを起動させたまま、bashで入れたりできます
- `volumes:　`では、永続化するvolumeの名前を指定してあげます

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

# Remove a potentially pre-existing server.pid for Rails.
rm -f /sample-app/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```

### Gemfile
```
source "https://rubygems.org"
gem "rails", "~> 7.0.4"
```
ここもローカル環境のrailsのバージョンと合わした方が後々エラーになりづらいです。
もしくは、ローカル環境でrailsのバージョンを合わせるようにしましょう。

### Gemfile.lock
ここは何も記述しなくて大丈夫です。

## rails newする
これでrails　newする準備はできたので、ターミナルで叩いていきましょう。
sample-appディレクトリのままで、下記を実行します。
```
docker-compose run web rails new . --force --database=postgresql
```
- webの部分は、docker-compose.ymlで記述した、web:の部分でこれがrails側のコンテナ名になります。
なので今後、docker-compose runやdocker-compose execなどを叩く時は、その後に指定した名前を記述してください。
- --apiをつけると、apiモードで作成できます
- --database=postgresqlでdbを導入できます。他にもmysqlなどがあります。
- --css=bootstrapなどとつけるとcssフレームワークも一緒に導入できます。他にもtailswind、bulma、postcss、sassも選べます。ただし、ここでtailwindを指定すると、[tailwindcss-rails](https://github.com/rails/tailwindcss-rails)というgemが自動で導入されます。これがdaisyUIを導入できない問題につながってしまったので、ここでは指定しない方が良いです。

#### config/database.ymlが作成されるので、以下を記述
rails newすると、sample-app以下にたくさんファイルが作成されると思います。
その中にconfig/database.ymlがあるので、以下のように記述してください。
```config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: postgres
  password: password #これは、docker-compose.ymlで指定したパスワード
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  <<: *default
  database: sample_app_development

test:
  <<: *default
  database: sample_app_test

production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %> #これを記述するだけで、あとはherokuがよしなにやってくれます
```
## ビルドしつつ、サーバーを起動
以下をターミナルで叩きます。
```
docker-compose up -d --build
```
やっていることは下記と同じです。
```
docker-compose build
docker-compose up -d
```
## localhost:3000 にブラウザでアクセス
アクセスすると`ActiveRecord::NoDatabaseError`が表示されると思います。
これは、dbを作成してくださいということなので、docker-compose exec web rails db:createしてください。
![スクリーンショット 2023-05-19 11.35.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/88238966-7879-5ad2-e534-10301c5892d4.png)
この画面が出たら、無事成功です。

# ページの作成
tailwindとdaisyuiを当てる前に、まずはてきとーにページを作りましょう。
今回は、コンテナは起動したままコマンドを叩くため、`docker-compose exec web`とします。起動していない時は、`docker-compose run web`で大丈夫です。
- トップページを作成
```
docker-compose exec web rails g controller Tops index
```
- `route.rb` と `tops/index.html.erb`を編集
```routes.rb
Rails.application.routes.draw do
  root "tops#index"
end
```
```index.html.erb
<h1 class="text-3xl font-bold underline">
    Hello world!
</h1>

<button class="bg-gray-900 hover:bg-gray-800 text-white rounded px-4 py-2">tailwind</button>

<button class="btn">daisyUI</button>
```

`http://localhost:3000/`にアクセスすると、以下のようになっていると思います。
現時点ではtailwindのスタイルとdaisyUIのスタイルがあたっていないですね。
![スクリーンショット 2023-05-25 20.13.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/84e30175-a29a-396b-c0ac-2205bf14db7c.png)

# tailwindとdaisyuiの導入
それでは、導入していきましょう。
とは言っても、tailwindとdaisyuiに関しては、下記の記事で説明してくれています。
ぜひ、一度見てみてください。

1. https://zenn.dev/yoiyoicho/articles/410a7e3fd892b5
2. https://qiita.com/kwtuku/items/3639e8f268f6f9a442b1 
3. https://qiita.com/345dvl/items/4bafb05964281079033e


導入方法としては、1.に記載してある通りなのですが、dockerを使った例をこの記事でも載せておきます。

## 手順
### 1. Gemfileに以下を記載

```
gem 'cssbundling-rails'
gem 'jsbundling-rails'
```

### 2. bundle install
`docker-compose exec web bundle install`をターミナルで入力し、budle installします

### 3.tailwindをインストール 
`docker-compose exec web bundle exec rails css:install:tailwind`でtailwindをインストールします。
`http://localhost:3000/`にアクセスすると、以下のようにtailwindが当たっていると思います。
![tailwind.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/eefc04af-569f-dc9c-7116-6668a5cc8967.png)


### 4. yarnでdaisyUIをインストール
続いて、daisyuiを導入していきましょう。
`docker-compose exec web yarn add daisyui`をターミナルで入力
`package.json`にインストールできているか確認してみましょう。
```package.json
{
  "name": "app",
  "private": "true",
  "dependencies": {
    "autoprefixer": "^10.4.14",
    "daisyui": "^2.51.6",
    "esbuild": "^0.17.19",
    "postcss": "^8.4.23",
    "tailwindcss": "^3.3.2"
  },
  "scripts": {
    "build:css": "tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css --minify",
    "build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets"
  }
}
```

package.jsonに追加できていることを確認できたら、`tailwind.config.js`に`plugins: [require("daisyui")]`を追記

```tailwind.config.js
module.exports = {
  content: [
    './app/views/**/*.html.erb',
    './app/helpers/**/*.rb',
    './app/assets/stylesheets/**/*.css',
    './app/javascript/**/*.js'
  ],
  plugins: [
    require('daisyui')
  ]
}
```
`config/manifest.js`を以下のように変更しておきます
```
//= link_tree ../images
//= link_tree ../builds
```

そして、ターミナルで`docker-compose exec web ./bin/dev`と入力すると、daisyUIのスタイルがあたっていると思います。
![スクリーンショット 2023-05-19 19.38.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/c49e600c-da7b-6516-88c3-0af5ef1af7bd.png)

## ちなみに
daisyUIには、いろいろテーマがありテーマに沿ったデザインに変更することができます。
 → https://daisyui.com/docs/themes/
例えば、`bumblebee`にしたい場合は、下記のように変更することでできます。（他にも色々な方法があったはずです）
```tailwind.config.js
module.exports = {
  content: [
    './app/views/**/*.html.erb',
    './app/helpers/**/*.rb',
    './app/assets/stylesheets/**/*.css',
    './app/javascript/**/*.js'
  ],
  plugins: [
    require('daisyui')
  ],
  daisyui: {
    themes: [
      "bumblebee"
    ],
  },
}
```
そして、`docker-compose exec web ./bin/dev`と叩くことで、そのテーマに応じたデザインに変更されると思います。
```index.html.erb
<h1 class="text-3xl font-bold underline">
    Hello world!
</h1>

<button class="bg-gray-900 hover:bg-gray-800 text-white rounded px-4 py-2">tailwind</button>

<button class="btn">daisyUI</button>

<button class="btn btn-secondary">btn btn-secondary</button>
```

![スクリーンショット 2023-05-19 20.24.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2521935/1cd28a51-3de9-2b48-0112-57655d0b578e.png)


## 補足
デザインを変更する度に./bin/devをしなければならず、手間になります。おそらく、その都度./bin/devを叩かなくてもいい方法があると思うのですが、知見のあるかたがいれば、ぜひコメント欄で教えていただけると嬉しいです。

## ポイント
- 今回は、Dockerでnodeのバージョンを指定し、daisyUIを導入しました。
[こちら](https://daisyui.com/docs/install/)に、いろいろなインストール方法があるので、参考にしてみてください。
- daisyUIを導入する際は、'gem `cssbundling-rails`、`gem 'jsbundling-rails'`でtailwindを追加するようにしましょう。

# さいごに
ここまで長々と書きましたが、あくまでもこの記事では一例であり、もっといい方法があるかもしれません。
至らぬ点もあるかと思いますので、修正点があれば何なりとお申し付けください🙇🏻‍♂️
ここまで見ていただき、ありがとうございました。

下記に、githubのURLを載せておきます。良ければ参考にしてみてください。

https://github.com/golfhiro/docker_rails_daisyui

# 参考記事
- [tailwind ドキュメント](https://tailwindcss.com/)
- [daisyUI コンポーネント](https://daisyui.com/)
- [【Rails7】TailwindCSS + daisyUIを導入する](https://zenn.dev/yoiyoicho/articles/410a7e3fd892b5)
- [Rails7 のフロントエンド関連の Gem を分類
](https://qiita.com/kwtuku/items/3639e8f268f6f9a442b1)
- [Rails 7でTailwind CSSを使ってみた
](https://qiita.com/345dvl/items/4bafb05964281079033e)