2018/1/17
第二十九天:卡米狗發公告
今天我們要作的是主動傳訊息的功能。
目前我們用到的都只是回覆訊息的功能:
# 認識 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)
```
我們需要傳遞 channel_id,告訴 Line 誰應該收到這個訊息,channel_id 就是 userId, groupId 或 roomId。所以我們需要一個資料模型去保存所有頻道的 channel_id。
文件參考在這裡:[https://developers.line.me/en/docs/messaging-api/reference/#send-push-message](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/active_record_querying.html#find-or-create-by](https://rails.ruby.tw/active_record_querying.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 表單輔助方法](https://rails.ruby.tw/form_helpers.html)
### 改 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`,這個函數我們待會才會寫。
### push_to_line
```
# 傳送訊息到 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 基礎](https://rails.ruby.tw/active_job_basics.html#%E4%BB%BB%E5%8B%99%E6%8E%92%E7%A8%8B) 以及 [Delayed Job (DJ)](https://devcenter.heroku.com/articles/delayed-job)。
自己摸這個要有花上一週的心理準備,加油加油加油,你是最棒的,耶!
# 本日重點
- 學會記錄頻道
- 學會主動發訊息
- 學會寫 view 的表單
沒意外的話,明天就講怎麼查天氣。
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言