概要
- うさぎ飼い始めました
- その中で出てきたニーズをWebアプリにしました
コード
- https://github.com/junara/usareco
-
https://usareco.herokuapp.com
で活用しています。しかし、登録されたユーザー(自分)以外だとエラーになりますのでリンクにしていません。
うさぎのペレット量の計算は面倒くさい
- 体重 * XX %で決まる
- XXは体重と月齢の関数で算出
- 毎日計算するの面倒くさい
やりたいこと
- 体重量ったらペレット量がすぐ知りたい
作るもの
- 体重を聞いて、ペレット量を返すBOT
作ったもの
全体像
動作動画
Slack連携のところ
-
参考
-
Slack Event API
- slack event apiでアプリを作っておく
- Event subscriptions:
- Request URL:
/api/rabbits/:token/slack
(:token
はrabbit毎に固有のtoken。)作っておく - Subscribe to Workspace Events: message.channels
- Bot User: 適当な名前で作る。今回は
usagi
- Incoming Webhooks: 特定のチャンネル(今回は
#rabbit
)にBOTがレスポンスを返すためのwebhook URLを取得します。このURLをDBに入れておく(rabbit.slack_webhook_url)。
- Request URL:
- Event subscriptions:
- 上記アプリを管理画面からslackにインストールしておく
- slack event apiでアプリを作っておく
-
Rails側は上記postを受けて以下を実行
- メッセージ中の数字を今日の体重として保存
- 体重からペレット量を計算
- Incoming webhookでslackへ投稿
- (ポイント)Botによるslackへの投稿で発火しないように
@body['event']['subtype'] == 'bot_message'
の場合はslack通知をしないようにする
- (ポイント)Botによるslackへの投稿で発火しないように
- slackへの投稿はgem
slack-notifier
をつかいました
app/controllers/api/rabbits_controller.rb
class Api::RabbitsController < Api::ApplicationController
protect_from_forgery except: [:slack]
def slack
rabbit = Rabbit.find_by(token: params[:token])
return unless rabbit.present?
body = JSON.parse(request.body.read)
case body['type']
when 'url_verification'
render json: body
when 'event_callback'
unless from_bot?(body) # BOTが無限に会話しないようにユーザーからの発言のみに応答するため
num = body['event']['text'].match(/\d+/).present? ? body['event']['text'].match(/\d+/)[0] : nil # 数値を正規表現で取得
feeding = rabbit.feeding(date: Time.current) # 今日の日付
if feeding.body_weight.present? # newの場合
feeding.body_weight.update(gram: num)
else # updateの場合
feeding.builds
feeding.body_weight.assign_attributes(gram: num, scaled_at: Time.current)
feeding.body_weight.save
end
if rabbit.slack_webhook_url # slackへ投稿。予めwebhook_urlを取得してDBに入れておく。
notifier = Slack::Notifier.new(rabbit.slack_webhook_url)
message = "ぼくの体重は#{feeding.body_weight.gram}g。ペレットは1日#{rabbit.ideal_pellet_gram&.round(1)}gでおねがいね![くわしくはこちら](#{root_url}) 。"
notifier.ping(message)
end
end
head :ok
end
end
private
def from_bot?(body)
body['event']['subtype'] == 'bot_message'
end
end
ペレット量の計算はこちら。
app/models/rabbit.rb
def ideal_pellet_gram
return unless latest_body_weight
latest_body_weight_gram = latest_body_weight.gram
coefficient = if latest_body_weight_gram < 400
0.07
elsif age_of_month <= 6
0.05
elsif age_of_year < 5
0.02
elsif age_of_year >= 5
0.01
end
latest_body_weight_gram * coefficient
end