Lambda for Ruby を使って勤怠ボタンを作ってみた

# 概要

弊社では勤怠の管理に jobcan というサービスを利用しています。slack連携で特定のコマンドを入力すると出勤・退勤ができるっていうグッドでナイスな感じのサービスなのですが、人は怠惰なものでもはや出勤時にslackに `/jobcan_touch` の13文字を打つのすらめんどい。

そこでせっかくなので先日発表された「[AWS Support for Ruby](https://aws.amazon.com/jp/about-aws/whats-new/2018/11/aws-lambda-supports-ruby/)」を利用して更に楽に出勤してみるをしてみることにしました。

lambda for ruby をちょっと触ってみたい人にも参考になると幸いです。

# 仕組み

すでに下記とほぼ同内容の仕組みが IFTTT 版で動いてるためその時にpythonで書いてたものをrubyでやってみるという感じです。

参考: [物理出勤ボタンを作った - レタスのかわをぜんぶむく](http://uskey.hatenablog.com/entry/2018/10/17/115728)

## やりたい仕組みの流れ

オフィスのドアを開ける → ポケットからiPhoneを取り出す → IFTTT Button を押す → (ここから自動) → AWS API Gatewayで設定したURLにPOSTする → フックされた Lambda が動く→ slack にcommand を投稿する → jobcan連携が飛ぶ → 出勤！

をオフィスに入ってから自席につくまでにやる、です。親指がslack開く(1)・チャネル開く(1)・13文字打つ(13)の15アクションの削減ですね。

## 手順

下記の手順でやったことを書いていきますが、IFTTTのアカウント作成はたぶん興味ある人いないと思うし、AWSのアカウントも迷うことなく登録できると思うし、太字のところから書いていこうと思います。

* IFTTTアカウントを作成する
* AWSアカウントを作成する
* **Rubyコードを書く**
* **lambdaの準備**
* **IFTTT ボタンの設定**
* **実行**

# Rubyコードを書く

## ハマりどころ

Rubyでslackに投稿するコードを書いていきます。上に上げたリンクにも書いてあるんですが2つほど注意点があります。

1つ目は、「レガシートークンを使う」です。
今回の投稿はslackの連携commandを使うので本人の投稿として認識させる必要があります。そのためIncomming Webhookが使えません。レガシートークンの取得はちょっと調べれば出てくると思います。

2つ目は、「ドキュメントに記載されてないAPIの chat.command にあたる命令をする必要がある」です。
今回 以下のgemを使ってますが、公式のドキュメントに記載がないAPIなのでこのgemのリファレンスにも乗ってないコマンドだったりします。

https://github.com/slack-ruby/slack-ruby-client

どちらも公式が推奨してない感じがプンプンしているので、いつか使えなくなる日が来るかも知れないんですがその頃にはjobcanさんがAPIを公開していただけるとありがたいです。出勤だけでいいので。

## コード

さて、コードはこんな感じです。

```
# Gemfile
source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
gem 'slack-ruby-client'
```

```lambda_function.rb
require 'slack-ruby-client'

TOKEN_ID = ENV['TOKEN_ID']

def lambda_handler(event:, context:)
  Slack.configure do |config|
    config.token = TOKEN_ID
  end

  client = Slack::Web::Client.new
  begin
    client.chat_command(
      channel: '#times_katsumata',
      command: '/jobcan_touch',
      text: 'by AWS Lmabda for Ruby via IFTTT',
      as_user: true
    )
  rescue => e
    {statusCode: 422, body: JSON.generate({class: e.class, message: e.message})}
  end

  {statusCode: 200, body: JSON.generate({message: 'ok'})}
end
```

コードのとおりなのですが、注意点としては

* lambdaのコード実行のスタートが `lambda_function.rb` の `def lambda_handler` から実行されます。そのためこれがないとlambdaにファイルを上げた時に警告がでます。
* 3行目: lambdaは環境変数が登録できるのでトークンは環境変数に登録してます
* 12行目: `client.chat_command` が先程のドキュメントに載ってないAPIのメソッド
* 13行目: 投稿チャネル
* 14行目: jobcanの出勤するスラック連携のコマンドtextだと文章として認識してしまうため、別にcommandで指定する必要があります。
* 16行目: `as_user: true` で本人としてslackに投稿ができるようになります。

という感じです。非公式コマンドのところは参考にしたサイトを見つけられなかったら確実に諦めてた案件でした。

# lambdaの準備

## アップロードファイルの準備

lambdaの準備をしていきます。
今回外部ライブラリを使用しているので、AWS lambdaのエディタを使うことができません。そのためzipにしてファイルをアップロードする必要があります。また、今回は4.3MBぐらいだったので必要なかったんですが、10MBを超えるとlambdaでのアップロードができません。その場合はS3にアップロードをする方向で対応してみてください( 参考: [Announcing Ruby Support for AWS Lambda](https://aws.amazon.com/jp/blogs/compute/announcing-ruby-support-for-aws-lambda/) )

bundle installしてローカルにgemを用意する

```
$ bundle install
$ bundle install --deployment # ./vender/bundle にgemが入る
```

ファイルツリーの様子

```
./
├── Gemfile
├── Gemfile.lock
├── lambda_function.rb
└── vendor # gem が入ってる
```

ファイル構造がこんな感じになっているはずなので、この4つを選択してzipファイルにしてあげてください。

## AWSでlambdaの作成

AWSでlambdaを作っていきます。

lambdaのページを開いて関数の作成を押す。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/2b3f21f8-b6d5-85ca-dff5-41679acd5249.png)

一から作成で項目を入力しランタイムでRubyを選択する。2018/12/02時点だと ruby2.5 のランタイムのみ用意されているようですね。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/3c54125f-06f4-1cf8-f37e-ed947d697f37.png)

以下のような画面が出てくると思うので(※画面はすでに動いてる関数のものなので実際の画面とは異なります)、一番上のファイル名のところが選択されている状態になっているとページの下部に関数コードの編集画面が出ていると思います。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/c55fea4e-08bd-0a48-9773-ca00ac407b2c.png)

コードエントリタイプで.zipファイルをアップロードを選択し、先程zipに固めたファイルをアップロードします。アップロード選択し終わったらページ上部の保存を押すようにしてください。毎回忘れてあれ？ってなる。今回ライブラリを含んでいるので下記画像のようなinfoが出ていて、インラインコードの編集はできなくなってる。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/dfaaaf95-39fd-be6c-d897-349816956713.png)


次に環境変数の登録です。書いたコードに合わせて環境変数を登録します。値にしてしているのは、先程のslackのレガシートークンです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/52d601c6-313c-901a-bdcb-10b01d60121a.png)

最後にAPI Gatewayの設定をします。ない人はトリガーの追加からAPI Gatewayの設定を行ってください。
ここで作ったAPI エンドポイントが IFTTT Buttonで登録する値になります。
ちなみにlambdaはメソッドの投稿テストができるので、実際に全体で動かして見る前に関数のテストを試せるので便利です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/d109b8d5-c5b5-c006-2ab4-887d080cf8ab.png)

# IFTTT Buttonの設定

あとは特に説明するほどではないのでキャプチャだけ。設定はbuttonからwebhookです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/871515e3-2a25-7919-6302-5241c748f5f7.png)

で、iPhoneの方でIFTTTのアプリをダウンロードしてボタンを設定してあげるとこのような感じに。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/bc3d0ff2-b781-52cc-a120-15e97a1569f1.png)

これで準備完了です！(実装中に一回間違えてボタンを押してしまって、出勤してしまったため勤怠修正申請しなきゃいけない...)

# 実行

ボタンを押すとslackの投稿がこんな感じでされてよっしゃ。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/20865/917e9930-6de2-a829-7da2-87b39add0004.png)

以上lambda for ruby を使った勤怠ボタンの作成でした。

lambda for rubyですが個人的に待望の機能追加でずっと待ってたので先日の発表は歓喜でした。サーバ上から何かを実行し用とすると環境の準備がネックになって作るのやめっちゃったりとかのハードルがぐっと下がりそう。簡単なwebアプリケーションも動かせたりと夢が広がりまくりな感じがあるので、lambda for ruby 活用していきたいところ。

# 参考リンク

* http://uskey.hatenablog.com/entry/2018/10/17/115728
* https://aws.amazon.com/jp/blogs/compute/announcing-ruby-support-for-aws-lambda/
* https://github.com/slack-ruby/slack-ruby-client