今天我們要作的是主動傳訊息的功能。
目前我們用到的都只是回覆訊息的功能:
認識 Push Message API
# 傳送訊息到 line
def reply_to_line(reply_text)
return nil if reply_text.nil?
# 取得 reply token
reply_token = params['events'][0]['replyToken']
# 設定回覆訊息
message = {
type: 'text',
text: reply_text
}
# 傳送訊息
line.reply_message(reply_token, message)
end
上面這個函數是我們之前寫好的 reply_to_line
函數,裡面的最後一行:
line.reply_message(reply_token, message)
這是在呼叫 line 提供給我們的回覆訊息函數,而 line 也有提供讓我們主動發訊息的函數:
response = line.push_message(channel_id, message)
我們需要傳遞 channelid,告訴 Line 誰應該收到這個訊息,channelid 就是 userId, groupId 或 roomId。所以我們需要一個資料模型去保存所有頻道的 channel_id。
文件參考在這裡:https://developers.line.me/en/docs/messaging-api/reference/#send-push-message
保存所有頻道
建立資料模型
rails g model channel channel_id
建立一個資料表叫作 channel,裡面有個欄位叫作 channel_id。
資料庫遷移
rails db:migrate
bj4
儲存頻道
在主程式中加入一行:
Channel.create(channel_id: channel_id)
如果你覺得是這樣寫,那你就錯了,因為這樣會導致相同的資料會一直被存進去,到時候你發公告,同一個人就會收到超多次。
Channel.find_or_create_by(channel_id: channel_id)
先看有沒有相同的資料,如果已經有資料的話就不寫入。如果沒有資料才作寫入。這邊有詳細的說明:https://rails.ruby.tw/activerecordquerying.html#find-or-create-by
加入後的主程式長這樣:
def webhook
# 紀錄頻道
Channel.find_or_create_by(channel_id: channel_id)
# 學說話
reply_text = learn(channel_id, received_text)
# 關鍵字回覆
reply_text = keyword_reply(channel_id, received_text) if reply_text.nil?
# 推齊
reply_text = echo2(channel_id, received_text) if reply_text.nil?
# 記錄對話
save_to_received(channel_id, received_text)
save_to_reply(channel_id, reply_text)
# 傳送訊息到 line
response = reply_to_line(reply_text)
# 回應 200
head :ok
end
接下來要作一個後台網頁去發這個公告。我們會需要兩個 Action,一個 get new Action 用來顯示發公告的後台頁面,另一個 post create Action 用來接收發公告訊息的請求。
管理後台
這次我們手動新增,不使用產生器。
加 Route
修改 config/routes.rb
,新增一行:
resources :push_messages, only: [:new, :create]
這是加入一組資源,但我們只使用其中的 new 和 create。
加 Controller
在 app/controllers
資料夾下建立一個叫作 push_messages_controller.rb
的檔案:
class PushMessagesController < ApplicationController
before_action :authenticate_user!
# GET /push_messages/new
def new
end
# POST /push_messages
def create
end
end
我們檢查使用者必須先登入,然後開了兩個空的 Action,之後再回頭來改。
加 View
我們要在 app/views/push_messages
下新增一個檔案 new.html.erb
。
這是 new.html.erb
所需要的全部程式碼:
<%= form_with(url: '/push_messages', local: true) do |form| %>
<%= text_area_tag 'text' %>
<%= submit_tag "送出" %>
<% end %>
一個表單的開始是 <%= form_with ..... do ... %>
,結束是 <% end %>
。表單預設是用 post 方法,所以就不用特別寫出來。
<%= text_area_tag 'text' %>
是輸入文字框。
<%= submit_tag "送出" %>
則是送出按鈕。
如果要了解更多的話可以參考:Action View 表單輔助方法
改 Controller
我們在接收到請求之後要作發訊息的動作:
def create
text = params[:text]
Channel.all.each do |channel|
push_to_line(channel.channel_id, text)
end
redirect_to '/push_messages/new'
end
text = params[:text]
這是取得剛剛在輸入文字框填的文字
Channel.all.each do |channel|
... end
這段是指我們想要對每一個 channel 作一些事情。
push_to_line(channel.channel_id, text)
這是說我們要主動發訊息 text
給頻道 channel.channel_id
,這個函數我們待會才會寫。
pushtoline
# 傳送訊息到 line
def push_to_line(channel_id, text)
return nil if channel_id.nil? or text.nil?
# 設定回覆訊息
message = {
type: 'text',
text: text
}
# 傳送訊息
line.push_message(channel_id, message)
end
長得跟之前的 reply_to_line
有 87% 像,就不解釋了。
對一下程式碼
完整的 push_messages_controller.rb
應該長這樣:
require 'line/bot'
class PushMessagesController < ApplicationController
before_action :authenticate_user!
# GET /push_messages/new
def new
end
# POST /push_messages
def create
text = params[:text]
Channel.all.each do |channel|
push_to_line(channel.channel_id, text)
end
redirect_to '/push_messages/new'
end
# 傳送訊息到 line
def push_to_line(channel_id, text)
return nil if channel_id.nil? or text.nil?
# 設定回覆訊息
message = {
type: 'text',
text: text
}
# 傳送訊息
line.push_message(channel_id, message)
end
# Line Bot API 物件初始化
def line
@line ||= Line::Bot::Client.new { |config|
config.channel_secret = '9160ce4f0be51cc72c3c8a14119f567a'
config.channel_token = '2ncMtCFECjdTVmopb/QSD1PhqM6ECR4xEqC9uwIzELIsQb+I4wa/s3pZ4BH8hCWeqfkpVGVig/mIPDsMjVcyVbN/WNeTTw5eHEA7hFhaxPmQSY2Cud51LKPPiXY+nUi+QrXy0d7Hi2YUs65B/tVOpgdB04t89/1O/w1cDnyilFU='
}
end
end
發布和測試
自己試試看,你們需要練習自己解決卡關,要養成看 log 的習慣。
關於怎麼做鬧鐘
你需要把主動發訊息這件事情加入排程,請參考:Active Job 基礎 以及 Delayed Job (DJ)。
自己摸這個要有花上一週的心理準備,加油加油加油,你是最棒的,耶!
本日重點
- 學會記錄頻道
- 學會主動發訊息
- 學會寫 view 的表單
沒意外的話,明天就講怎麼查天氣。
沒有留言:
張貼留言