DockerでRailsチュートリアルのローカル開発環境構築 - RSpec導入 & CircleCIでHerokuデプロイ-

# はじめに

前回の記事
[DockerでRailsチュートリアルのローカル開発環境構築（Rails 6 + PostgreSQL + Webpack) - Qiita](https://qiita.com/daddy_hacker/items/99225bf3d8665ecfdec2)

個人開発アプリ
[mdClip ＜オンラインmarkdownエディタ＞](https://mdclip.xyz/)

前回の記事に続いて、Railsチュートリアルのローカル開発環境構築を行っていきます。

- Railsチュートリアル最新版（2020.8.6現在）に対応のRails 6

- Dockerを使用し、開発環境の再現が可能

- なるべくローカル環境にインストールしない

  

Docker環境で操作する場合はターミナルのコマンドを適宜

```
$ docker-compose run app ...
```

もしくは

```
$ docker-compose exec app ...
```

で置き換えてください。

# Rspec導入

minitestでも問題ないです
後述のCircleCIでもminitestを走らせる事もできました。

## Gemfile

必要に応じて以下のgemを追加
(不要ならminitest関連のgemを削除する)

`Gemfile`

```ruby
  # Test enviroment: Rspec
  gem 'rspec-rails'
  gem 'spring-commands-rspec'
  gem 'guard'
  gem 'guard-rspec', require: false

  # Test enviroment: Fake date generator
  gem 'factory_bot_rails'
  gem 'faker'
  gem 'forgery_ja'
```



## bundle install

Gemfileを編集したので`docker-compose build`が必要です

```
$ docker-compose build
```



## 初期ファイル生成

```
$ rails g rspec:install
```



## レポートフォーマット

 `.rspec`

```ruby
--require spec_helper
--format documentation
```



## Guard初期化

```
$ bundle exec guard init
```



## spring boot対応

```
$ bundle exec spring binstub --all
```

Guardの自動テスト時にもspringが有効になるように
`Guardfile`

```ruby
guard :rspec, cmd: "bundle exec spring rspec" do
```



# CircleCI設定

## 事前準備

ここでは説明しませんが事前に以下の手順が必要だと思います

- GitHub & CircleCI & Herokuのアカウント登録
- SSH接続設定(GitHub - CircleCI)
- CircleCIへのproject登録および環境変数定義(Heroku APIキー, app名)



## 設定概要

- `git push` -> 自動test (RSpec) -> 自動デプロイ(Heroku)
- Orbを使うと`config.yml`の内容を簡略化できる(キャッシュ利用のための記述が不要)
- Orbを使うために`version: 2.1`指定
- Docker imageのRuby versionはRailsチュートリアルに合わせて2.6.3
- Node.jsが必要なので-nodeのついたimageを指定

> **メモ:** Node.js バリアントの Docker イメージ (`-node` で終わるタグ) に対しては、Node.js の LTS リリースがプリインストールされています。 独自に特定のバージョンの Node.js/NPM を使用する場合は、`.circleci/config.yml` 内の `run` ステップで設定できます。 Ruby イメージと共に特定のバージョンの Node.js をインストールする例については、以下を参照してください。

公式サンプルを踏襲しています

CircleCI公式doc - Ruby
[Language Guide: Ruby - CircleCI](https://circleci.com/docs/2.0/language-ruby/#sample-configuration)

CircleCI公式doc - Heroku Deploy
[デプロイの構成 - CircleCI](https://circleci.com/docs/ja/2.0/deployment-integrations/#heroku-%E3%81%AE%E3%83%87%E3%83%97%E3%83%AD%E3%82%A4)



**現時点で最新のHeroku-orbは1.2.0ですがバグがあるようで
`pull request`されています**
[deploy-via-git bash script error · Issue #13 · CircleCI-Public/heroku-orb](https://github.com/CircleCI-Public/heroku-orb/issues/13)



## config.yml

`.circleci/config.yml`

```yml
version: 2.1

orbs:
  ruby: circleci/ruby@1.0
  node: circleci/node@2
  heroku: circleci/heroku@1.1.0

# setupでまとめる
commands:
  setup:
    steps:
      - checkout
      - ruby/install-deps
      - node/install-packages:
          pkg-manager: yarn
          cache-key: "yarn.lock"

jobs:
  build:
    docker:
      - image: circleci/ruby:2.6.3-node
    steps:
      - setup
  test:
    docker:
      - image: circleci/ruby:2.6.3-node
      - image: circleci/postgres:11.6-alpine
        environment:
          POSTGRES_USER: postgres
          POSTGRES_DB: myapp_test
          POSTGRES_PASSWORD: ""
    environment:
      BUNDLE_JOBS: "4"
      BUNDLE_RETRY: "3"
      PGHOST: 127.0.0.1
      PGUSER: postgres
      PGPASSWORD: ""
      RAILS_ENV: test
    steps:
      - setup
      - run:
          name: Wait for DB
          command: dockerize -wait tcp://localhost:5432 -timeout 1m
      - run:
          name: Database setup
          command: bundle exec rails db:schema:load --trace
      - run:
          name: Rspec
          command: bundle exec rspec

  deploy:
    executor: heroku/default
    steps:
      - checkout
      - heroku/install
      - heroku/deploy-via-git:
          maintenance-mode: true
      - run:
          name: DB migrate
          command: heroku run rails db:migrate --app $HEROKU_APP_NAME

workflows:
  version: 2
  test_and_deploy:
    jobs:
      - build
      - test:
          requires:
            - build
      - deploy:
          requires:
            - build
            - test
          filters:
            branches:
              only: master
```

# 動作確認

## HTMLを書き換える

`app/controllers/application_controller.rb`

```ruby
class ApplicationController < ActionController::Base
  def hello
    render html: "Bye, world!"
  end
end
```

変更をgit pushして、CircleCIのpipelineがsuccessに変われば
ブラウザから見た内容が上記を反映するはずです

## 簡単なテスト

仮のrequest_specを作成

```
rails g rspec:request test
```

`spec/requests/tests_spec.rb`

```ruby
require 'rails_helper'

RSpec.describe "Tests", type: :request do
  describe "GET /" do
    it "Bye, world!が表示されること" do
      get root_path
      expect(response.body).to include "Bye, world!"
    end
  end
end
```

CircleCI上でも上記テストがpassするはずです

# Troubleshoot

## CircleCIのtestが以下のエラーで失敗する

```
rails aborted!
PG::ConnectionBad: could not translate host name "db" to address: Name or service not known
```

`database.yml`の記述が原因です

test環境ではdefaultを引き継いで`host: db`が適応されているはずです

`config/database.yml`
以下のように書き換えて環境変数がある場合はそちらを優先するようにしました
（ymlのなかでもerbが使えるという学びでした）

```yml
test:
  <<: *default
  host: <%= ENV['PGHOST'] || 'db' %>
  database: myapp_test
```



## ERROR IN CONFIG FILE:

インデント、フォーマットの間違いが多いと思います


# 最後に

- 意地でローカル環境をきれいに保つことに注力した結果、デプロイやdb:migrateを自動化することで、Heroku CLIすらインストールすることを回避しましたが、素直にHeroku CLIくらいは入れておいた方が今後のエラー解決に役立つ気もします。
- 難易度は上がりますが、ローカル環境でDocker, CICDを取り入れてのRailsチュートリアル、学べることも多いと思いますので腰を据えて取り組むことのできる方はぜひトライしてみてください。
- 今後も未知のエラーに遭遇することが予想されますが、おおよそココまでが大変なところかとおもっていますので、この記事がお役に立てれば幸いです。