【Rails】Twitter APIとLINE APIでジャニーズの私物を特定して、すぐに購入できるサービスを作ってみた!!! PF [LINE API部分❶] (リッチメニューの切り替え)

#はじめに
PFで**ジャニーズの私物を特定して、すぐに購入できるサービス**を作成したのでまとめます。
あまりにも長くなりそうなので、今回は`LINE Messaging API`を使用した部分についてまとめます。

#サービスの概要

ジャニーズファンは推しと同じものを日常生活やライブで身につけたいという心理があります。
twitte上にファンの人が私物を特定してツイートをするので、そのツイートをキャッチして、LINEで通知・購入できるサービスになっています。

#なぜこのサービスを作成したか
私物の特定のツイートがされるとすぐファンが購入し、売り切れてしまうことがよくあります。
私自身、私物特定のツイートを発見し、サイトを検索してももう売り切れてしまっていたということが何回もあります。
他のファンよりも早く購入できるサービスがあればいいなと思い、このサービスを作成しました。

##完成したサービス
Webサイトは以下になります↓

https://www.findgoodsofstan.jp/

LINEのQRコードになります。
ぜひ動かしてみてください!!
<img width="150" alt="a163e5fa2b2098ef30926fb607faa8ff.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/a14102d3-51c9-2d22-8d96-89396b192b6d.png">

サービスのイメージがしづらいと思いますがこんな流れになります
1.Twitterで私服特定ツイートがされます。
<img width="150" alt="S__37232668.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/53b8694a-7863-28c2-f542-724b2666d617.jpeg">

2.LINEにこのような通知が届きます。
<img width="150" alt="S__37232670.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/655e3495-461c-9893-14ef-fbb72d2fd061.jpeg">

3.`商品検索ボタン`から検索可能です。
<img width="150" alt="S__37232676.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/0cac9a6b-b08e-177b-f1ba-8fc533464d59.jpeg">

4.`To tweetボタン`からソース元に遷移可能です。
<img width="150" alt="S__37232678aaa.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/eb20d86e-88f7-1fb5-41fe-7d4415d933ab.jpeg">

**LINE友達登録後できること**
1.最新の情報を確認できます。
リッチメニュー右上の`最新の情報ボタン`を押す→情報を確認したい`メンバーを選択`する→`最新の情報`が表示される
<img width="150" alt="S__37232679ss.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/8356275b-8543-573c-7977-8c0be57320cc.jpeg">

<img width="150" alt="S__37232680ss.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/5fd3ae36-11f3-2ab2-dee2-a141e96f05eb.jpeg">

2.情報を受け取るメンバーを選択できます。
リッチメニュー左上の`メンバー設定を変更する`を選択する→設定した`いメンバーを選択`する→通知を`受け取る`か、`受け取らない`かを選択する

<img width="150" alt="S__37232682b.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/4ff385cc-e26b-8c41-82b2-d8193d26bca5.jpeg">

<img width="150" alt="S__37232683b.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/bccb87c7-e4d8-4915-8ead-9572dff76465.jpeg">

もちろん、現在の通知設定についてもリッチメニュー左下の`メンバー設定を確認する` から確認可能です。

<img width="150" alt="S__37232681b.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/993e74a7-e425-3671-d2c8-32306ad510af.jpeg">


##使用した機能
Twitter API
LINE Messaging API
dotenv-rails'
config gem
ransack gem
sorcery gem
kaminari gem
enum_help gem
rails-i18n gem
AWS
heroku

##ER図
![3917056f5181a1ce73694684e344b358.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/c94b651d-f7d3-2072-fdc5-fd44e049b93d.png)

https://drive.google.com/file/d/10gO9reC8SdPK9OE3ZZntfC9CflYIkJHv/view?usp=sharing


##画面遷移図

![d657ee3591bde2b85796fbee48567573.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/26fd44d1-3ee1-0043-31c7-63dc3a8e16b1.png)

https://www.figma.com/file/pFrYU4hSwDQFn4da2XSTyh/Untitled?node-id=32%3A2



##LINE Messaging API

「LINE BOT」とは、メッセージアプリのLINEを使用して、ユーザーの質問に自動で返答できたり、メッセージを送信できたりするプログラムのことです。

https://developers.line.biz/ja/services/messaging-api/

仕組みについてはこちら↓

>Messaging APIを使って、ボットサーバーとLINEプラットフォームの間でデータを交換できます。リクエストは、JSON形式でHTTPSを使って送信されます。

>1.ユーザーが、LINE公式アカウントにメッセージを送信します。
>2.LINEプラットフォームからボットサーバーのWebhook URLに、Webhookイベントが送信されます。
>3.Webhookイベントに応じて、ボットサーバーからユーザーにLINEプラットフォームを介して応答します

https://developers.line.biz/ja/docs/messaging-api/overview/#how-messaging-api-works

###今回の目標
・LINEbotは一つで6人分の情報を送信したい
・友達登録してくれたユーザーが自分で受け取るメンバーを選択できるようにしたい
・メンバー設定等はLINE画面で、全てこなせるようにしたい

###考えなければならなかったこと
#####情報が欲しいユーザーだけに送信しなければならない
今回は`multicast`メソッドを使用して送信します。
このような形で、user_idsに情報が欲しいユーザーのLINEのuser_idを挿入して送信する形です。

```
user_ids = [user_id1, user_id2, ...]
client.multicast(user_ids, <message>)
```

このuser_idをどうやって取得するか...
まず最初に想定したのは、自分が作成したサービスにLINEアカウントでログインしてもらい、user_idを取得する方法です。
ですが、ログインすることに抵抗がある方や、めんどくささを感じてしまう方がいらっしゃると思ったので、今回は`リッチメニューを2種類作成`し、友達登録してもらった後の最初のトーク画面で、リッチメニューをタッチしてもらい、その時にサーバーに送られてくるレスポンスボディからuser_idを取得することにしました。

https://developers.line.biz/ja/docs/messaging-api/linking-accounts/


###1.gemを追加する

```ruby
# LINE API用
gem 'line-bot-api'
```
>LINE Messaging API SDK for Rubyを使用すると、LINE Messaging APIを使用してボットを簡単に開発でき、数分以内にサンプルボットを作成できます。

https://github.com/line/line-bot-sdk-ruby


###2.リッチメニューを作成する

####完成形
[友達登録後すぐ]
<img width="200" alt="1639715013543.jpeg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/d41234b6-078e-4795-6d36-16821c06b2f8.jpeg">

[デフォルトのリッチメニューをタッチしてもらい、user_idを取得した後、リッチメニューを切り替える]
<img width="200" alt="S__37134358_new.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/9101df08-3336-8c53-02f9-5a12a3e887b9.jpeg">

####前提として

#####Webhookとは

>Webhookとは、Webアプリケーションに対して、特定のイベントが発生したら別のWebアプリケーションに通知を発行するよう利用者が指定する仕組み。HTTPのPOSTリクエストを利用する。

https://e-words.jp/w/Webhook.html

###流れ
(前提として、LINEのアカウントは作成済みとします。)
1.リッチメニュー画像を2つ作成する
2.[Postman](https://www.postman.com/)を使用して、リッチメニューを登録する
3.Rails側でタッチされた際に、リッチメニューが切り替わるように設定する
####1.リッチメニュー画像を2つ作成する
今回はこの２枚を準備しました。
<img width="200" alt="S__37011492.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/2e058250-a26a-ed9d-0e43-35fd1ee29ee6.png">

<img width="200" alt="S__37011490.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/ae407998-11a1-9be3-0d77-32ce7f4fc8e4.png">

使用できるサイズ等に決まりがあるので注意します。

>リッチメニューの画像は以下の要件を満たす必要があります。

>画像フォーマット：JPEGまたはPNG
画像の幅サイズ（ピクセル）：800以上、2500以下
画像の高さサイズ（ピクセル）：250以上
画像のアスペクト比（幅/高さ）：1.45以上
最大ファイルサイズ：1MB

https://developers.line.biz/ja/docs/messaging-api/using-rich-menus/#prepare-a-rich-menu-image


####2.[Postman](https://www.postman.com/)を使用して、リッチメニューを登録する

参考にさせていただきました。もうこのサイトを見れば全てわかります。

https://qiita.com/mksanjeewa/items/831a1522ef161819ff2d

リッチメニューを登録する流れは、
#####1.リッチメニューを作成する
#####2.リッチメニューで表示する画像を設定する
#####3.一つをデフォルトのリッチメニューとして設定する

今回は、リッチメニューを2つ登録する必要があります。
なので、言葉で言うと、1.と2.を2回行いリッチメニューを２パターン作成します。そのうち、一つをデフォルトのリッチメニューとして設定し、もう一つを、リッチメニューをタッチしていただいた方に表示するという流れです。

#####1.リッチメニューを2個登録します
[Postman](https://www.postman.com/)を使用します。

1.新しいタブを開く
2.送信方法を**POST**に設定
3.エンドポイントに**https://api.line.me/v2/bot/richmenu**を設定
4.Authorizationタブを開き、TypeからBearer Tokenを選択する。
5.右側のToken欄に自分のチャネルのアクセストークンを設定
![3f84980ec91fa6bb1d07837ad1fe578d.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/a7c196ae-9a0b-2a01-38ed-c4aa0357ca2c.png)

6.Headersタブを開いてKeyはContent-TypeとValueはapplication/jsonに設定する

![82f9c23e7a8e0116bdde041c51e4a0af.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/09ceaf50-b626-0a1b-da12-d03fe3d17e72.png)

7.Bodyタブを開いてオプションからrawを選択する。
テキストボックスに自分のリッチメニューの設定を入力する。
公式はこちらから↓

https://developers.line.biz/ja/reference/messaging-api/#create-rich-menu

私の場合は

```
{
  "size": {
   "width": 1200,
   "height": 810
  },
   "chatBarText": "Tap to open",
   "name": "Nice richmenu",
   "selected": true,
   "areas": [
   {
    "bounds": {
       "x": 0,
       "y": 0,
       "width": 1200,
       "height": 810
     },
     "action": {
        "type": "postback",
        "data": "start"
     }
     }
   ]
}
```

8.**send**ボタンを押す

9.status:200 OKと表示され、**richMenuId**(リッチメニューのID)が表示される。
この**richMenuId**はまた使います。

**richMenuId**がわからなくなったら、以下で探せます
<リッチメニューの配列を取得する>
送信方法 → GET
エンドポイント → https://api.line.me/v2/bot/richmenu/list
Authorization：Bearer {channel access token}

#####2.リッチメニューの画像をアップロードする

1.送信方法をPOSTに設定
2.エンドポイントにhttps://api-data.line.me/v2/bot/richmenu/{richMenuId}/content を設定。
{richMenuId}は送られてきたレスポンスの**richMenuId**を入れる。
![3762371cc7ef14649c23f0a9499f0606.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/46141333-a024-e087-f2c2-24f66110a26c.png)
3.Content-Typeはimage/jpeg、image/pngのように自分の画像の拡張子で設定
![43c075255102a12b489bced0ee60d673.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/e1bdda55-23e9-4961-5c8b-ae1767bd49c2.png)

4.Bodyタブからbinaryを選択し、ファイルから自分の画像を選択
![77c36c8f5ae01b44aff53b80c7761d36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/2cb292bd-aaa5-cabc-3703-994afb740e25.png)
5.**send**ボタンを押す
6.status:200 OKと表示されればOK

この流れでリッチメニューを2パターン作成します。

#####3.作成したリッチメニューの一つをデフォルトに設定する

まず、最初の「まずはこちらをタッチ」の方のリッチメニューをデフォルトに設定します。
デフォルトに設定したことにより、友達登録をしていただいたときには全員にこのリッチメニューが表示されます。

<デフォルトのリッチメニューを設定する>
送信方法 → POST
エンドポイント → https://api.line.me/v2/bot/user/all/richmenu/{richMenuId}
Authorization：Bearer {channel access token}

もう一つの方のリッチメニューはRailsの方で設定します。

###リッチメニューのボタンをタッチした際に、切り替えされるよう設定する

まず上で設定したデフォルトの方のリッチメニューのbodyの中身は以下のようになっています。これを参考にまとめていきます。

```
{
  "size": {
   "width": 1200,
   "height": 810
  },
   "chatBarText": "Tap to open",
   "name": "Nice richmenu",
   "selected": true,
   "areas": [
   {
    "bounds": {
       "x": 0,
       "y": 0,
       "width": 1200,
       "height": 810
     },
     "action": {
        "type": "postback",
        "data": "start"
     }
     }
   ]
}
```

###方法・流れ
リッチメニューを押した際に、サーバーに送られてくるリッチメニューレスポンスオブジェクトの内容を判断し、反応を組み込んでいく。

まず、リッチメニューオブジェクトについて。

>リッチメニューは以下のどちらかのオブジェクトで表されます。

>リッチメニューIDを含まないリッチメニューオブジェクト。リッチメニューの作成時にこのオブジェクトを使用します。
リッチメニューIDを含むリッチメニューレスポンスオブジェクト。リッチメニューの取得時またはリッチメニューの配列の取得時にこのオブジェクトが返されます。
これらのオブジェクトは領域オブジェクトとアクションオブジェクトから構成されます。

https://developers.line.biz/ja/reference/messaging-api/#rich-menu-structure

**流れ**
1.リッチメニューを作成するときにリッチメニューレスポンスオブジェクトに含ませたい内容を組み込む
2.Railsでリクエストボディを取得した時の対応を組み込む


####1.リッチメニューを作成するときにリッチメニューレスポンスオブジェクトに含ませたい内容を組み込む

**リッチメニューオブジェクト**は
>これらのオブジェクトは領域オブジェクトとアクションオブジェクトから構成されます。

https://developers.line.biz/ja/reference/messaging-api/#area-object


ということなので、`領域オブジェクト`と`アクションオブジェクト`について理解したいです。。


**領域オブジェクト**
**bounds**と**action**が必須です。
**bounds** : 領域の境界をピクセルで表すオブジェクト。= タッチして反応する領域を決めます。

ここの部分で領域を指定しています。

```
"bounds": {
       "x": 0,
       "y": 0,
       "width": 1200,
       "height": 810
     }
```

**action** : 領域がタップされたときに実行されるアクション。↓でまとめている(アクションオブジェクト)のこと。

**アクションオブジェクト**

>ユーザーがメッセージ内のボタンまたは画像をタップしたときに、ボットが実行できるアクションのタイプです。

https://developers.line.biz/ja/reference/messaging-api/#action-objects

私が使用したのは、**ポストバックアクション**です。
>このアクションが関連づけられたコントロールがタップされると、dataプロパティに指定された文字列を含むポストバックイベントが、Webhookを介して返されます。

以下の部分です。上記のように、リッチメニューがタッチされると、dataプロパティに指定された`"start"`を含むポストバックイベントが返されます。

```
"action": {
        "type": "postback",
        "data": "start"
     }
```


####2.Railsでリクエストボディを取得した時の対応を組み込む
Rails側で対応を設定します。

```ruby:line_users_controller.rb
def line_responce
    #LINE Messaging API認証
    line_client ||= Line::Bot::Client.new { |config|
      config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
      config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
    }
      body = request.body.read
      signature = request.env['HTTP_X_LINE_SIGNATURE']
      unless line_client.validate_signature(body, signature)
        error 400 do 'Bad Request' end
      end
      #request.bodyを解析する
      events = line_client.parse_events_from(body)
      events.each do |event|
        #dataの中身が"start"だったら処理を実行させる
        data = event['postback']['data']
        if data == "start"
          #user_id取得
          userId = event['source']['userId']
          LineUser.start(userId)
        end
      end
    head :ok
end
```
`LineUserモデル`に`line_user_idカラム`を作成済みです。
レスポンスボディに含まれるLINEのuseridが、存在していなければ保存し、リッチメニューを切り替えます。

```ruby:line_user.rb
def self.set_user_richmenue(user_id)
    if LineUser.find_by(line_user_id: user_id)
      @lineuser = LineUser.find_by(line_user_id: user_id)
    else
      @lineuser = LineUser.new(line_user_id: user_id)
      @lineuser.save!
    end
  client.link_user_rich_menu("#{user_id}", "#{もう一つのリッチメニューID}")
end
```

```ruby:routes.rb
post '/line_responce', to: 'line_users#line_responce'
```
https://developers.line.biz/ja/reference/messaging-api/#create-rich-menu

####試しに動かしてみる

開発環境で動かすときは
`ngrok`を使用します。ここではngrokの説明は省きます

1.`rails s`を実行する
2.`ngrok http 3000`を実行する
3.`ngrok`に表示される`https://~.ngrok.io`までをコピーする
4.LINE developersのページの`Webhook設定`のとことに設定する
今回はroutes.rbに書いた通り使用したいので、こんな感じで入力し、更新ボタンを押す
![637bfe8e30dc94f4323fa07d4af99c41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133440/9ce8514d-8a28-7a45-2c53-8c00b1a4072f.png)
5.検証ボタンが表示されるので、押してみて200が表示されればOK
6.自分のLINEページで、デフォルトのリッチメニューをタッチしてみると
ターミナルでこのように確認することができる。

```
Processing by LineUsersController#line_responce as HTML
  Parameters: {"destination"=>"***", "events"=>[{"type"=>"postback", "postback"=>{"data"=>"start"}, "timestamp"=>**, "source"=>{"type"=>"user", "userId"=>"**"}, "replyToken"=>"**", "mode"=>"active"}], "line_user"=>{}}
```

Paramsの中を確認すると、`events"=>[{"type"=>"postback", "postback"=>{"data"=>"start"}`このような感じで指定した`start`が取得できている。

これを、`line_users_controller.rb`で`if data == "start"`の形で判断させ処理を実行させている。
7.LINEの画面を確認すると、デフォルトのリッチメニューからもう一つのリッチメニューに変更されている

以上の流れでリッチメニューの切り替えを行いました。