はじめに
LineBotの作成の際に
「都道府県の選択を簡単に行えればいいな〜」
「対話形式で都道府県選択を行いたいな〜」
と思ったので自作してみました。
まだまだプログラミング初心者なので、DRYになっていない部分多々ありますが興味あればご覧ください。
基本的なLineBot作成方法は下記の記事などを参考にしてください。(すごく分かりやすいです。)
今更ながらRails5+line-bot-sdk-ruby+HerokuでLineBot作成してみたら、色々詰まったのでまとめました。
環境
- Ruby on rails
- heroku
作ったもの
下記の手順で都道府県を選択できるようにしました。
①地域の選択肢を、クイックリプライで表示させる。
②ユーザーが地域を選択する。
②選択した地域に含まれる各都道府県を、クイックリプライで表示させる。
④ユーザーが都道府県を選択する。
⑤LineBot側で選択された都道府県を認識してメッセージが来る。
以下がイメージ画像です。
※今回作成する部分は「どこの地域で遊ぶ?」〜「東京都で遊ぶ!」までの部分です。
→ →
灰色の部分がクイックリプライと呼ばれる機能で、タッチするとMessageType::Text
として送信されます。
作成方法
概要
①都道府県モデル(Prefectureモデル)とseedデータ作成。
②地域と都道府県選択のためのmessageを用意。
③linebot_controllerのcallbackアクションに、分岐を作成。
といった流れで作成していきます。
①都道府県モデルとseedデータ作成。
まずは都道府県モデル(Prefectureモデル)を作成していきます。
$bundle exec rails g model Prefecture name:string
$bundle exec rails db:migrate
その後、都道府県データを作るためにseedをいじっていきます。
# 47都道府県の配列を作る。
prefectures = [ "北海道", "青森県", ・・・・・・ "沖縄県" ]
# prefecturesの配列を元にデータ作成する。
prefectures.each do |prefecture|
Prefecture.create!(
name: prefecture
)
end
作成できたら
$bundle exec rails db:seed
これで下記のようなデータが出来るはずです。
id | name |
---|---|
1 | 北海道 |
2 | 青森県 |
・・・ | ・・・ |
47 | 沖縄県 |
②地域と都道府県選択のためのmessageを用意。
LineBotからリプライされるメッセージを作っていきます。
非常に量が多いため、app/controllers/linebot_controller.rb
には記載せず、
今回はapp/models/line_clinet.rb
に記載しました。
app/models/line_clinet.rbのサンプルコード
class LineClient
# 1回目の質問(地域選択部分)
def self.first_reply
{ "type": "text",
"text": "どこの地域で遊ぶ?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "北海道,東北",
"text": "北海道,東北"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "関東",
"text": "関東"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "甲信越,東海",
"text": "甲信越,東海"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "関西,北陸",
"text": "関西,北陸"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "中国,四国",
"text": "中国,四国"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "九州",
"text": "九州"
}
}
]
}
}
end
# 2回目の質問(都道府県の選択部分)
def self.second_reply_hokkaido_tohoku
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "北海道",
"text": "北海道"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "宮城県",
"text": "宮城県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "青森県",
"text": "青森県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "岩手県",
"text": "岩手県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "秋田県",
"text": "秋田県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "山形県",
"text": "山形県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "福島県",
"text": "福島県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
def self.second_reply_kanto
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "東京都",
"text": "東京都"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "神奈川県",
"text": "神奈川県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "千葉県",
"text": "千葉県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "埼玉県",
"text": "埼玉県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "群馬県",
"text": "群馬県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "栃木県",
"text": "栃木県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "茨城県",
"text": "茨城県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
def self.second_reply_kousinnetu_tokai
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "山梨県",
"text": "山梨県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "長野県",
"text": "長野県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "新潟県",
"text": "新潟県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "愛知県",
"text": "愛知県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "岐阜県",
"text": "岐阜県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "三重県",
"text": "三重県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "静岡県",
"text": "静岡県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
def self.second_reply_kansai_hokuriku
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "大阪府",
"text": "大阪府"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "京都府",
"text": "京都府"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "兵庫県",
"text": "兵庫県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "奈良県",
"text": "奈良県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "和歌山県",
"text": "和歌山県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "滋賀県",
"text": "滋賀県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "石川県",
"text": "石川県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "富山県",
"text": "富山県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "福井県",
"text": "福井県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
def self.second_reply_chugoku_shikoku
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "広島県",
"text": "広島県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "岡山県",
"text": "岡山県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "山口県",
"text": "山口県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "鳥取県",
"text": "鳥取県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "島根県",
"text": "島根県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "香川県",
"text": "香川県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "愛媛県",
"text": "愛媛県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "徳島県",
"text": "徳島県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "高知県",
"text": "高知県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
def self.second_reply_kyusyu
{ "type": "text",
"text": "どの県で遊ぶの?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "福岡県",
"text": "福岡県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "佐賀県",
"text": "佐賀県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "長崎県",
"text": "長崎県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "熊本県",
"text": "熊本県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "大分県",
"text": "大分県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "宮崎県",
"text": "宮崎県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "鹿児島県",
"text": "鹿児島県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "沖縄県",
"text": "沖縄県"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
# 3回目の質問
def self.third_reply(prefecture)
{ "type": "text",
"text": "#{prefecture}で遊ぶでいい?",
"quickReply": {
"items":
[
{
"type": "action",
"action": {
"type": "message",
"label": "#{prefecture}で遊ぶ!",
"text": "#{prefecture}で遊ぶ!"
}
},
{
"type": "action",
"action": {
"type": "message",
"label": "地域を選び直す",
"text": "地域を選び直す"
}
}
]
}
}
end
end
変数を渡したりしたいので、基本的にはmethodとして定義しています。
③linebot_controllerのcallbackアクションに、分岐を作成。
送信されるメッセージに応じて、LineBotの返信メッセージを変えていきます。
想定通りのフローでユーザーが動くと
first_reply
second_reply_〇〇
third_reply
の順に表示されて、反応していくことになります。
app/controllers/linebot_controller.rbのサンプルコード
class LinebotController < ApplicationController
require 'line/bot'
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)
# 作った都道府県データを再度変数に保存しておく。
prefectures = Prefecture.all
events.each { |event|
#ここでLINEで送った文章を取得。スペースなどの空白は削除
@message = event.message['text'].gsub(" ", "")
# eventの種類による場合分け(MesageやBeaconなどがあります)
case event
when Line::Bot::Event::Message # Event::Messageの場合の処理
case event.type
when Line::Bot::Event::MessageType::Text # MessageType::Textの場合の処理
case @message # 送信されたメッセージに応じて分岐させる。
# 地域選択された際に、該当地域の各都道府県を表示する部分。←2枚目の画像の部分
when "北海道,東北"
message = ::LineClient.second_reply_hokkaido_tohoku
client.reply_message(event['replyToken'], message)
when "関東"
message = ::LineClient.second_reply_kanto
client.reply_message(event['replyToken'], message)
when "甲信越,東海"
message = ::LineClient.second_reply_kousinnetu_tokai
client.reply_message(event['replyToken'], message)
when "関西,北陸"
message = ::LineClient.second_reply_kansai_hokuriku
client.reply_message(event['replyToken'], message)
when "中国,四国"
message = ::LineClient.second_reply_chugoku_shikoku
client.reply_message(event['replyToken'], message)
when "九州"
message = ::LineClient.second_reply_kyusyu
client.reply_message(event['replyToken'], message)
# Prefectureモデルに該当するメッセージの場合に反応する。←3枚目の画像の部分
when *prefectures.pluck(:name) #prefecturesのnameカラムに値があるものに反応するように記載。
prefecture = Prefecture.find_by(name: @message)
message = ::LineClient.third_reply(prefecture.name)
client.reply_message(event['replyToken'], message)
# 最初の質問部分(設定以外のテキストが送られてきた場合に表示) ←1枚目の画像の部分
else
message = ::LineClient.first_reply
client.reply_message(event['replyToken'], message)
end
end
end
}
head :ok
end
end
まとめ
コードを見ていただくと分かる通り、実はメッセージによって分岐させているだけなので、一番初めに「北海道」などと送信すると、LineBotは対話形式を無視していきなり反応してしまいます。欠陥品です。(笑)
「(笑)じゃねーよ、もっといい方法あるだろがボケ」と思われている方いらっしゃると思いますので、もし思われている方いればいい方法教えて欲しいです。(gemとかどっかにありそう)
おまけ
もしよければ「ずぼらデート」というLineBotを作ったので、友達登録してみてください。