Rails＋heroku+LINE Messager APIで秘書的なLINEbotを作ってみた（ゴミ出しの通知編）


![IMG_7844.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224974/373d9a29-65a5-2b56-1112-fdce053fe945.png)

#作るもの
毎日決まった時間になるとゴミ出しについて通知してくれる簡単なLINEbot。
ゆくゆくは天気/交通情報/イベントなども共有してくれるbotにしたいと思っています。
アイアンマンに出てくる人工知能ジャーヴィスをお節介おばさんにしたイメージです。

![dims.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224974/c083e4cc-75ea-4191-5a46-e18ec9c91104.jpeg)


#使用した言語/フレームワーク/ライブラリ/サービス
-Ruby
-Ruby On Rails6
-Heroku
-LINE Messager API

#大まかな手順
1.メッセージをオウム返しするLINEbotを作る
2.LINEにメッセージをpushしてみる
3.Herokuにデプロイして定期実行する

#STEP１　メッセージをオウム返しするLINEbotを作る
##LINE MessagerAPI
作成したbotのメッセージ周りのやり取りを担当してくれるのがLINEMessage APIです。
まず、自分のメッセージの内容をそのまま返してくれるbotを作ります。
LINE Messager APIの概要はDeveloperページを確認。
[LINE Developers](https://developers.line.biz/ja/services/messaging-api/)

###APIの準備
APIを使用する前にやるべきことがいくつかあります。ざっくりとこんな感じ。
1. ビジネスアカウントの登録
2. プロバイダーの作成
3. チャンネルの作成
4. グループ・複数人チャットへの参加を許可するにチェック
5. Messaging APIの「Channel access token」と「channel Secret」を控える

「[LINEのBot開発 超入門（前編） ゼロから応答ができるまで](https://qiita.com/nkjm/items/38808bbc97d6927837cd#%E6%89%8B%E9%A0%86)」　登録周りを丁寧に説明しているので、わからなくなったらこっちを参考にしてください。

###Rails側の実装
ここからは、「[今更ながらRails5+line-bot-sdk-ruby+HerokuでLineBot作成してみたら、色々詰まったのでまとめました。](https://qiita.com/y428_b/items/d2b1a376f5900aea30dc)」を参考に実装します。

まずRailsのプロジェクトを作ります。herokuがデフォルトでpostgresqlなので、合わせます。

```console
$Rails new mother_bot --database=postgresql
$rails db:create
```

Line APIを使う為のgemをインストールします。

```Gemfile.rb
#LINE API用
gem 'line-bot-api'

#access tokenなどを管理する用
gem 'dotenv-rails' 
```

```console
$bundle install
```

LINE API登録時に控えた情報をアプリのルート直下に.envファイルを作成して保存

```.env
#.env
LINE_CHANNEL_SECRET=XXXXXX
LINE_CHANNEL_TOKEN=XXXXXX
```

コントローラーの準備をしてきます。

```console
$rails g controller Linebot
```


```linbot_controller.rb
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']
          }
        end
      end
    }

    head :ok
  end
end
```

```config/route.rb
Rails.application.routes.draw do
  post '/callback' => 'linebot#callback'
end
```

###ローカルでデバッグしてみる
herokuにpushしておしまい！のような記事が多いので、ローカルのデバッグで苦労しました。
ローカルからAPIを操作するためにはまずngrokを使う必要があります。参考記事を読みながら、デバッグ環境を構築してください。

公式サイト
https://ngrok.com/

参考記事（ローカルで動かす　セクションからが重要）
[LINE Botをローカル環境で動かしたりデバッグしたりする方法](https://qiita.com/TakeshiFukushima/items/aec362407f1ee2f455a9#3-%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%AB%E3%81%A7%E5%8B%95%E3%81%8B%E3%81%99)

###TIPS
- ngrokuを導入する際は、公式サイトからemailを登録してインストラクションに剃ってダウンロード、コマンドを叩いてくと正常に動くようになります。
- LINE DevelopersからWebhook URLを設定を正しくするというのが、一番のミソだと思います。
- ngrokuは無料プランだと起動するたびにエンドポイントが変わるので、Webhook URLを毎回変えましょう。

STEP1終了
これでうまく実装できていれば、自分のLINEから作成したアカウントを友達登録して、メッセージを投げると同じ内容のメッセージを投げ返してくれます。友達登録は、LINE DeveloperのチャンネルページのQRコードを使うと簡単です。

![IMG_7845.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224974/6a10c2b3-abe9-1ebf-d74e-da63dd60665b.png)

初期メッセージはLINE Developersから編集できます。

#STEP２　LINEにメッセージpushする
STEP１では、自分のメッセージをトリガーに、LINE Message APIを操作しました。
今回は、チャンネルがこちらのアクションなしで、テキストを送信できるよう実装していきます。

###ユーザーモデルの追加
messageをAPIから一方的に送りつけるためには、rails側で送り先のuserIDを知っている必要があります。
送るユーザーが決まっていればIDをメモして、環境変数に設定してもいいと思いますが、今回はお友達登録でユーザーIDを保存できるように、実装します。

```console
$rails g model user uid:string
$rails db:migrate
```

###controllerに追記
```linebot_controller.rb
        #省略 
        #29行目ぐらい
        when Line::Bot::Event::MessageType::Text
          message = {
            type: 'text',
            text: event.message['text']
          }
          client.reply_message(event['replyToken'], message)
        when Line::Bot::Event::MessageType::Follow #友達登録イベント
          userId = event['source']['userId'] 
          User.find_or_create_by(uid: userId)
        when Line::Bot::Event::MessageType::Unfollow　#友達削除イベント
          userId = event['source']['userId']  
          user = User.find_by(uid: userId)
          user.destroy if user.present?
        end
      
```

###タスクを追加

決まった時間になったら、メッセージを送りつける為のタスクを作成します。

```lib/tasks/push.rake
namespace :push_line do 
    desc "LINEBOT：ゴミ出しの通知" 
    task push_line_message_trash: :environment do
        trash_day = TrashDay.new
        message = {
            type: 'text',
            text: trash_day.text
        }
        client = Line::Bot::Client.new { |config|
            config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
            config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
        }
        User.all.each do |user|
            client.push_message(user.uid, message)
        end
    end
end
```

曜日によってメッセージが違うので、メソッドを切り出しました。必要ない人は無視で！

```trash.rb
class TrashDay
    def text
      date = Date.today
    
      case date.strftime('%a')
        when "Mon"
            "ちょっとあんた！今日は月曜日、普通ゴミの日だわ！" + metal_text
        when "Tue"
            "ちょっとあんた！今日は火曜日、空き缶・ペットボトル・空き瓶・使用済み乾電池の日だわ！"
        when "Wed"
            "ちょっとあんた！今日は水曜日、プラスチック製容器包装の日だわ！"
        when "Thu"
            "ちょっとあんた！今日は木曜日、普通ゴミの日だわ！"
        when "Fri"
            "HEY BUDDY! It's Friday. Party hard. Don't drink too much.(ゴミ無しの日)"
        when "Sat"
            "ちょっとあんた！今日は土曜日、ミックスペーパーの日だわ！"
        else
            ""
        end
    end

    def metal_text
        date = Date.today
        week = DateHelper.new.week_of_month_for_date(date)
        day = date.strftime('%a')
        if week == 2 || week == 4
            "２・４回目の月曜日だから小物金属も忘れちゃダメよ！"
        else
            ""
        end
    end
end
```


隔週で回すタスク用のメソッドです。

```date_helper.rb
class DateHelper
    def week_of_month_for_date(date)
        my_date = Time.zone.parse(date.to_s)
        week_of_target_date = my_date.strftime("%U").to_i
        week_of_beginning_of_month = my_date.beginning_of_month.strftime("%U").to_i
        week_of_target_date - week_of_beginning_of_month + 1
    end
end
```

タスクが登録されたか確認

```console
$rails -T
```

実行してみる

```
rails push_line:push_line_message_trash
```

メッセージが届いたら成功です！
STEP２終了

#STEP3　Herokuにデプロイして定期実行する
これで９割完成です。あとはherokuにアップして、定期実行の設定をしてみましょう。

まずherokuのアカウントとアプリを作成します。
この辺は、記事を参考に進めてください。

HerokuにRailsアプリをデプロイする手順
https://qiita.com/NaokiIshimura/items/eee473675d624a17310f

一通りherokuデプロイの手順が終わったら、LINEAPIの環境変数を設定していきます。

```console
$heroku config:set LINE_CHANNEL_SECRET=xxxx
$heroku config:set LINE_CHANNEL_TOKEN=xxx

#herokuの時間を日本時間に合わせます
$heroku config:add TZ=Asia/Tokyo
```


herokuのURLをAPIのWebhookURLに設定するのを忘れないでください。
<img width="1615" alt="スクリーンショット 2019-12-01 16.16.48.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224974/f6a2731e-d39c-dc75-4538-de9a2bb7433e.png">


###定期実行の設定
通常であれば、wheneverみたいなgemを使ってcronを操作すると思いますが、今回はherokuでのデプロイなので、heroku schedulerというaddonを使って実装します。無料です。

参考記事
Herokuでスケジューラ（cron）を設定する方法【Heroku Scheduler】
https://reasonable-code.com/heroku-cron/


```console
#addonの追加
$heroku addons:create scheduler:standard --app アプリ名

#heroku上でタスクが動くか確認
$heroku run bundle exec rails push_line:push_line_message_trash --app アプリ名
```

実際に定期実行してみる

```
#GUI上でスケジュールを設定
$heroku addons:open scheduler

#実行されてるか確認
$heroku logs --app アプリ名
```

以上です。これで決まった時間にメッセージが送られてきたら成功です！
お疲れ様でした。

#感想

簡単なLINEbotでしたが、とても楽しかったです。機会があればgoogle calendar APIなどと連携してbotの秘書力を高めて行きたいです。