91
86

More than 5 years have passed since last update.

Rails HerokuでLINE BOTを試してみた

Last updated at Posted at 2016-04-09

追記

この記事はトライアル版時代のものになります。すでに正式版が出ているので、ご注意ください。

Railsで今話題のLINE BOTを作ってみました。
とりあえず、送ったメッセージをそのまま返すものです。

LINEへの登録

https://business.line.me から登録できます。

デベロッパー登録が済めば、次のような画面が出てくるので、

  • Channel ID
  • Channel Secret
  • MID

の値を控えておきます。

スクリーンショット 2016-04-09 14.43.14.png

HerokuにRailsアプリを作成

LINE BOT API の呼び出しには Server IP Whitelist に接続元 IPを登録する必要があるんですが、HerokuのFixieというアドオンを使うと、プロキシを経由してくれるのでIPを固定できます。
参考) LINE BOT をとりあえずタダで Heroku で動かす

とりあえず空のRailsアプリをHerokuにデプロイして、下記コマンドでFixieアドオンを追加してください。

$ heroku addons:create fixie:tricycle

Heroku上で作ったアプリの設定画面から Fixie の画面を開くと次のような画面になるので、

  • Proxy URL
  • Outbound IPs

を控えます。

スクリーンショット 2016-04-09 15.06.11.png

そして、LINE DevelopersのServer IP Whitelistに控えたIPが2つあると思うので2つとも登録しておきます。

スクリーンショット 2016-04-09 14.43.51.png

CallbackURLの設定

BOTに対してメッセージを送るとWebhookでcallback先に情報が飛んでくるのでcallbackURLを設定します。
HTTPSしか許可してくれないんですが、HerokuはもともとHTTPSなのでこの点はクリアです。
自分のサーバでやるときはSSLとかを頑張らないといけないです。
(証明書を使っても、無料のLet's Encryptだとうまく動かないなどの罠があるみたいです。参考

下記のようにBasic Informationのところに設定します。ポート番号の443も必須みたいです。

スクリーンショット 2016-04-09 14.43.35.png

自分の場合、CallbackURLを設定してから反映するまで結構時間がかかりました。
1時間以上経ってからコールバックしてきたので、なにか間違ったかといろいろいじり倒してしまいました。
自分を信じて気長に待つ事をオススメします。

Railsアプリ

本題?のRailsアプリです。

まず、Basic Informationに設定したCallbackURLを受け付けるようroute.rbを書きます。

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

次にコントローラです。
WebhookなのでCSRF対策を無効化してます。
is_validate_signatureメソッドはLINE公式ドキュメントのコピペです。

app/controllers/webhook_controller.rb
class WebhookController < ApplicationController
  protect_from_forgery with: :null_session # CSRF対策無効化

  CHANNEL_ID = ENV['LINE_CHANNEL_ID']
  CHANNEL_SECRET = ENV['LINE_CHANNEL_SECRET']
  CHANNEL_MID = ENV['LINE_CHANNEL_MID']
  OUTBOUND_PROXY = ENV['LINE_OUTBOUND_PROXY']

  def callback
    unless is_validate_signature
      render :nothing => true, status: 470
    end
    result = params[:result][0]
    logger.info({from_line: result})
    text_message = result['content']['text']
    from_mid =result['content']['from']

    client = LineClient.new(CHANNEL_ID, CHANNEL_SECRET, CHANNEL_MID, OUTBOUND_PROXY)
    res = client.send([from_mid], text_message)

    if res.status == 200
      logger.info({success: res})
    else
      logger.info({fail: res})
    end
    render :nothing => true, status: :ok
  end

  private
  # LINEからのアクセスか確認.
  # 認証に成功すればtrueを返す。
  # ref) https://developers.line.me/bot-api/getting-started-with-bot-api-trial#signature_validation
  def is_validate_signature
    signature = request.headers["X-LINE-ChannelSignature"]
    http_request_body = request.raw_post
    hash = OpenSSL::HMAC::digest(OpenSSL::Digest::SHA256.new, CHANNEL_SECRET, http_request_body)
    signature_answer = Base64.strict_encode64(hash)
    signature == signature_answer
  end
end

次にLINE BOT APIを呼ぶ自作ライブラリです。
Faradayを使うので、Gemfileに

Gemfile
gem "faraday"
gem "faraday_middleware"

を追加しておいてください。

lib/line_client.rb
require "faraday"
require "faraday_middleware"
require "json"
require "pp"

class LineClient
  module ContentType
    TEXT = 1
    IMAGE = 2
    VIDEO = 3
    AUDIO = 4
    LOCATION = 7
    STICKER = 8
    CONTACT = 10
  end
  module ToType
    USER = 1
  end

  END_POINT = "https://trialbot-api.line.me"
  TO_CHANNEL = 1383378250 # this is fixed value
  EVENT_TYPE = "138311608800106203" # this is fixed value

  def initialize(channel_id, channel_secret, channel_mid, proxy = nil)
    @channel_id = channel_id
    @channel_secret = channel_secret
    @channel_mid = channel_mid
    @proxy = proxy
  end

  def post(path, data)
    client = Faraday.new(:url => END_POINT) do |conn|
      conn.request :json
      conn.response :json, :content_type => /\bjson$/
      conn.adapter Faraday.default_adapter
      conn.proxy @proxy
    end

    res = client.post do |request|
      request.url path
      request.headers = {
          'Content-type' => 'application/json; charset=UTF-8',
          'X-Line-ChannelID' => @channel_id,
          'X-Line-ChannelSecret' => @channel_secret,
          'X-Line-Trusted-User-With-ACL' => @channel_mid
      }
      request.body = data
    end
    res
  end

  def send(line_ids, message)
    post('/v1/events', {
        to: line_ids,
        content: {
            contentType: ContentType::TEXT,
            toType: ToType::USER,
            text: message
        },
        toChannel: TO_CHANNEL,
        eventType: EVENT_TYPE
    })
  end
end

環境変数に、

  • LINE_CHANNEL_ID
  • LINE_CHANNEL_SECRET
  • LINE_CHANNEL_MID
  • LINE_OUTBOUND_PROXY

を使っているので、控えた値をもとに設定しておいてください。
LINE_OUTBOUND_PROXYの値はポート番号付きで最後の:80を忘れないようにしてください。
Herokuだと、

$ heroku config:add LINE_CHANNEL_ID="XXXXXXXXXXXX"
$ heroku config:add LINE_CHANNEL_SECRET="XXXXXXXXXXXX"
$ heroku config:add LINE_CHANNEL_MID="XXXXXXXXXXXX"
$ heroku config:add LINE_OUTBOUND_PROXY="XXXXXXXXXXXX"

という感じになります。

これで、BOTと友達になって、メッセージを送りつけると、そのまま返してくるはずです。

Basic InformationのところのQRコードを使ったら、友達になれます。
まだトライアルなので50人までしか友達増やせないみたいです。

91
86
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
91
86