rails環境新規構築(importmap + bootstrap)

# はじめに
rails の新規構築って、初回しか利用しないので利用頻度が低く、rails7から色々な組み合わせもできるようになったので、少し調査した結果を備忘録として残します

# 準備

初期ファイルの生成
```sh:コマンド
touch compose.yml
mkdir app
touch app/Dockerfile.dev
touch app/Gemfile
touch app/Gemfile.lock
touch app/template.rb
```

```sh:compose.yml
services:
  app:
    container_name: app
    build:
      context: ./app
      dockerfile: Dockerfile.dev
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - 3000:3000
    depends_on:
      - mysql
    volumes:
      - ./app:/app
      - bundle_data:/usr/local/bundle
    environment:
      RAILS_ENV: development
      DB_HOST: mysql
      DB_NAME: root
      DB_PASSWORD: password
    tty: true

  mysql:
    container_name: mysql
    image: public.ecr.aws/docker/library/mysql:8
    environment:
      MYSQL_ROOT_PASSWORD: password
      TZ: "Asia/Tokyo"
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:
  bundle_data:
```


```sh:Dockerfile.dev
FROM public.ecr.aws/docker/library/ruby:3.2-slim

RUN apt-get update -y -qq \
    && apt-get install -y build-essential libpq-dev default-libmysqlclient-dev git \
    && rm -rf /usr/local/bundle/cache/* /usr/local/share/.cache/* /var/cache/* /tmp/*

ENV TZ Asia/Tokyo

WORKDIR /app

# gem
COPY Gemfile* /app/
RUN gem update --system && \
    bundle update --bundler && \
    bundle install

COPY . /app
```


```sh:Gemfile
source 'https://rubygems.org'
gem 'rails'
```

```sh:template.rb
def add_rspec_gem
  gem 'rspec'
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'capybara', '>= 2.15'
  gem 'faker'
  gem 'spring-commands-rspec'
end

def rspec_setup
  run 'rm -rf test'
  run 'bundle install'
  run 'rails g rspec:install'
  file '.rspec', <<~CODE
    --require spec_helper
    --format documentation
    --color
  CODE
end

def add_rubocop_gem
  gem 'rubocop', require: false
  gem 'rubocop-performance', require: false
  gem 'rubocop-rails', require: false
end

def rubocop_setup
  run 'bundle install'
  run 'bundle exec rubocop --auto-gen-config > /dev/null'

  file '.rubocop.yml', <<~CODE
    inherit_from: .rubocop_todo.yml

    require:
      - rubocop-performance
      - rubocop-rails

    AllCops:
      SuggestExtensions: false
      # 最新のルールを適用する
      NewCops: enable
      # 何のルールに引っかかったか表示する
      DisplayCopNames: true
      # rubocop対象外(リポジトリ毎で調節)
      Exclude:
        - "Gemfile"
        - "bin/**/*"
        - "db/**/*"
        - "log/**/*"
        - "tmp/**/*"
        - "vendor/**/*"
        - "lib/tasks/auto_annotate_models.rake"
        - "config/environments/*"
        - "config/puma.rb"

    # 日本語にコメントを許可
    Style/AsciiComments:
      Enabled: false

  CODE
end

def add_dev_gem
  gem 'annotate'
  gem 'solargraph'
end

def dev_setup
  run 'bundle install'
  run 'rails g annotate:install'
end

def add_gems
  gem_group :development, :test do
    add_rspec_gem
    add_dev_gem
  end
  gem_group :development do
    add_rubocop_gem
  end
end

###############################
# Main setup
###############################
add_gems

after_bundle do
  rspec_setup
  rubocop_setup
  dev_setup
end
```

# 初期構築（rails new）
rails new
```sh:コマンド
docker compose build
docker compose run --rm app rails new .  \
--database=mysql  \
--skip-action-mailer \
--skip-action-mailbox  \
--skip-test   \
--javascript=importmap  \
--force   \
-m template.rb
```

DBの接続先を登録
```sh:app/config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV.fetch("DB_NAME") %>       # ←この行を修正
  password: <%= ENV.fetch("DB_PASSWORD") %>   # ←この行を修正
  host: <%= ENV.fetch("DB_HOST") %>           # ←この行を修正
```

DB生成(一部過剰ですが)
```
docker compose run --rm app bundle exec rails db:drop db:create db:migrate db:seed
```

デフォルトページを表示
```
docker compose up
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/8eeb7b19-ed22-6ea3-4a63-dab60d34470a.png)



# トップページを生成
```sh:コマンド
docker compose run --rm app rails g controller top index
```

```sh:app/config/routes.rb
Rails.application.routes.draw do
  get 'top/index'
  root 'top#index'   # ←この行を修正
  # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html

  # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
  # Can be used by load balancers and uptime monitors to verify that the app is live.
  get "up" => "rails/health#show", as: :rails_health_check

  # Defines the root path route ("/")
  # root "posts#index"
end
```

```sh:app/app/views/top/index.html.erb
<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-dark">Dark</button>

<button type="button" class="btn btn-link">Link</button>


<div class="btn-group">
  <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
    Action
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><a class="dropdown-item" href="#">Another action</a></li>
    <li><a class="dropdown-item" href="#">Something else here</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a class="dropdown-item" href="#">Separated link</a></li>
  </ul>
</div>
```

bootstrapが当たってないので、こんな感じの画面が表示されます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/68351661-09fa-99a2-51eb-ebca8a7667cd.png)

# bootstrap設定

こちらの記事を参考にさせていただきました

https://inuinu.jp/rails7-bootstrap-importmap/


```sh:app/Gemfile
gem 'bootstrap'
gem "mini_racer"
gem 'sassc-rails'
```

```sh:コマンド
docker compose build --no-cache
docker compose run --rm app bundle install
```

importmap設定を追記
```sh:コマンド
echo 'pin "popper", to: "popper.js", preload: true' >> app/config/importmap.rb
echo 'pin "bootstrap", to: "bootstrap.min.js", preload: true' >> app/config/importmap.rb
```

css関係の設定を追記
```sh:コマンド
mv app/app/assets/stylesheets/application.css app/app/assets/stylesheets/application.scss
echo '@import "bootstrap";' >> app/app/assets/stylesheets/application.scss
```

js関係の設定を追記
```sh:コマンド
echo 'Rails.application.config.assets.precompile += %w( bootstrap.min.js popper.js )' >> app/config/initializers/assets.rb
echo 'import "popper"' >> app/app/javascript/application.js
echo 'import "bootstrap"' >> app/app/javascript/application.js
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3632357/c40b9274-3e18-3ca0-dff5-8714cc38d0ba.png)


# おまけ
開発する上で、自動リロードしてくれるのでとても便利でした
導入するかどうかは、お好みで

```sh:app/Gemfile
group :development do
  gem "rubocop", require: false
  gem "rubocop-performance", require: false
  gem "rubocop-rails", require: false
  gem "rails_live_reload"         # ←この行を修正
end
```
以下のコマンドを追加
```
docker compose build --no-cache
docker compose run --rm app bundle install
docker compose run --rm app rails generate rails_live_reload:install
```

# さいごに
今回はimportmapを利用した新規構築を調べました。
正直hotwireで何処までできるのかは分かってないので、調べていく必要はあると考えています。
ただ、reactが使いたい！とかchakraUIを使いたい！というケースもありますので、他のパターンも後々記事にしていこうかと思います