Line botをrails5+Docker+Herokuでデプロイ備忘録

# 目標
- RubyonRails5(RoR)開発環境をdocker-composeで構築
- Herokuへデプロイ
- LINE DVELOPERSで新規チャネル作成
- オウム返しBOTの作成

# 前提条件
※MACの方が対象です。
- home brewでgit,herokuのインストール済み
- dockerインストール済み
- Heroku,gitHub,Dockerで会員登録済み

## RoR開発環境構築

```terminal
$ mkdir Linebot
$ cd Linebot
$ vi Dockerfiles
```

```Docker:Dockerfile
# ruby2.3.3のイメージレイヤの上で下記のコマンド実行しますよ宣言
FROM ruby:2.3.3
# apt-getはパッケージマネージャみたいなやつ
# updateでリスト更新＆必須なパッケージをインスト
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

# 作業ディレクトリの作成、設定
RUN mkdir /app_name 
##作業ディレクトリ名をAPP_ROOTに割り当てて、以下$APP_ROOTで参照
ENV APP_ROOT /app_name 
WORKDIR $APP_ROOT

# ホスト側（ローカル）のGemfileを追加する
ADD ./Gemfile $APP_ROOT/Gemfile
ADD ./Gemfile.lock $APP_ROOT/Gemfile.lock

# Gemfileのbundle install
RUN bundle install
ADD . $APP_ROOT
```

```terminal
$ vi docker-compose.yml
```

```yml:docker-compose.yml
version: '3'
services:
  db:
    image: postgres:13.0
    environment:
      POSTGRES_PASSWORD: 'postgres'
    ports:
      - "3306:3306"

  web:
    build: .
    command: rails s -p 3000 -b '0.0.0.0'
    volumes:
      - .:/app_name
    ports:
      - "3000:3000"
    depends_on:
      - db
```

webとdbというコンテナ起動

```terminal
$ touch Gemfile.lock
$ vi Gemfile
```

```:Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 5.2.2'
```

```terminal
$ docker-compose run app rails new . --force --database=postgresql --skip-bundle
$ docker-compose build -d
$ docker-compose up -d web
```

-dオプションはデタッチモードで起動する（ログを流さずバックエンドで動作させる）
ログを見たいなら外していいけど止めるとコンテナも止まるから面倒
※dockerfileに手を加えたときだけ再度ビルドする必要があるので注意
※docker-compose.ymlの更新なら再度upする必要あり

```yml:/config/database.yml
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db
  username: postgres
  password: postgres
....
production:
  <<: *default
  database: app_name_production
  username: postgres
  password: <%= ENV['APP_NAME_DATABASE_PASSWORD'] %>
```
開発、本番でpostgresqlを使うと書いておく
後述のHerokuを使う場合、postgresqlが標準だからよき
まあMySQLでもいいっちゃいいんだけどさ

```ruby:Gemfile
#LINE API用
gem 'line-bot-api'

#access tokenなどを管理する用(環境変数管理)
gem 'dotenv-rails'

#heroku環境用postgresql
gem 'pg'
```

```terminal
$ docker-compose run web bundle install
$ docker-compose run web rails db:create
$ docker-compose run web rails g controller top index
$ docker-compose run web rails g controller linebot collback
```

データベース作っておかないと怒られるよ
Herokuでtop画面が必要なので何でもいいからとりあえず作っておこう
(volumeをコマンドだけじゃなくて直でいじったりはあんまりよくない気がするけど無視無視)

```ruby:routes.rb
post '/callback' => 'linebot#callback'
root 'top#index'
```

```ruby:/app/controllers/linebot_controller
class LinebotController < ApplicationController
    require 'line/bot'  # gem 'line-bot-api'

  # callbackアクションのCSRFトークン認証を無効
  protect_from_forgery :except => [:callback]

  def client
    @client ||= Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
  end

  def callback
    body = request.body.read

    signature = request.env['HTTP_X_LINE_SIGNATURE']
    unless client.validate_signature(body, signature)
      head :bad_request
    end

    events = client.parse_events_from(body)

    events.each { |event|
      case event
      when Line::Bot::Event::Message
        case event.type
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: event.message['text']
          }
          client.reply_message(event['replyToken'], message)
        when Line::Bot::Event::MessageType::Image, Line::Bot::Event::MessageType::Video
          response = client.get_message_content(event.message['id'])
          tf = Tempfile.open("content")
          tf.write(response.body)
        end
      end
    }

    head :ok
  end
end
```

```terminal
$ touch .env
```

```text:.env
LINE_CHANNEL_SECRET=XXXXXXXXXXX
LINE_CHANNEL_TOKEN=XXXXXXXXXXX
```
XXXXXXXXXXXはあとで作成するLine Developersのやつを書いてね
もしもローカルのコンテナを落としたいなら
`$ docker-compose down`
でやったらOK
Ctl+Cとかで落とした場合
`$ rm tmp/pids/server.pid`
をやっておいた方がよき


## Herokuへのデプロイ

```terminal
$ vi heroku.yml
```

```yml:heroku.yml
build:
  docker:
    web: Dockerfile
run:
  web: bundle exec puma -C config/puma.rb
```

これ書いておかないとビルドできないよ
heroku.ymlでdevelopment/productionの切り替えとかそれに伴うdbの切り替えとかもできそう（やってない）

```terminal
$ heroku login
$ heroku create
$ heroku addons:create heroku-postgresql:hobby-dev
$ heroku container:login
$ heroku container:push web
$ git init
$ heroku git:remote -a <自分のherokuリポジトリ名>
$ git add .
$ git commit -am "いい感じのコメント"
$ heroku stack:set container
$ git push heroku master
$ heroku container:release web
$ heroku open
```

ブランチ切らないなら今後はgitと同じくaddしてcommitしてheroku pushで更新していけるよ神かな？
この辺、コンテナプッシュしたりイメージプッシュしたりごちゃっとしてるのであんまり真似しない方がいいかも

- なんかサーバーの調子がおかしいときは
`$ heroku restert`
を打ってみたらよき
- ログを確認したいときは
`$ heroku logs --tail`
でおk
- サーバーのファイルを見たいなら
`$ heroku run bash`
でcatコマンド打ったりで見たら良き（vimが使えんのがお怒りポイント）


## Lineのチャネルとコンテナを接続

- Messaging APIでチャネル作成
- チャネルシークレットとチャネルアクセストークンを発行して.envファイルに貼り付けておく
- webhookを有効にするために応答メッセージと挨拶メッセージをオフに
- webhookを有効にしたらwebhookURLに<自分のURL>/callbackを入力して検証（成功にならなければheroku restartとかしてみて）

### おまけ
テストしたいけどデプロイまでしたくない！ローカルで外部公開したい！
ngrok使うがよろし

とりあえず検証でリクエスト送りたい！
Talend API Tester使うがよろし

### お世話になった記事
LINEのBot開発 超入門（前編） ゼロから応答ができるまで
https://qiita.com/nkjm/items/38808bbc97d6927837cd

DockerComposeでコンテナベースのRailsアプリを作成してHerokuにデプロイする
https://qiita.com/akirakudo/items/16a01271b0a39316e439

丁寧すぎるDocker-composeによるrails5 + MySQL on Dockerの環境構築(Docker for Mac)
https://qiita.com/azul915/items/5b7063cbc80192343fc0

Deploying Rails Applications with the Puma Web Server
https://devcenter.heroku.com/articles/deploying-rails-applications-with-the-puma-web-server