Rails から Slackに通知してみる

今回は、タイトルの通り Rails から Slack に通知を出してみます。
関連で、Active Job・Delayed Job にも触れることができて、収穫がありました。

Slack とやり取りできる gem

Slack とやり取りできる gem を調べました。
ほかにもありそうですが、以下の 2 つを見つけました。

今回は、github - stevenosloan / slack-notifierを使ってみます。
以降は、github - stevenosloan / slack-notifierを見ながら作業します。

事前準備

Slack のアカウントを取ります。

Slackにサインインします。

Incoming Webhook を有効にします。

通知に使用するためIncoming Webhookを有効にします。
有効にするとき、表示された Webhook URL を後々使うので控えておきます。

この画面で、通知時に表示される名前やアイコン画像・説明をカスタマイズできますが、今回はこのままです。

実装

今回は、新しく DB にアイテムが追加されたとき slack に通知されることを目指します。

slack-notifier gem の導入

Gemfile を編集します。

Gemfileに追記
1
gem "slack-notifier"

編集できたら、bundle installを実行します。

model の作成

scaffold を使用して、作ってしまいます。

1
2
3
4
5
# scaffoldでモデル他を作成
bundle exec rails g scaffold user name:string

# DBにマイグレーションを実行
bundle exec rails db:migrate

コントローラを編集

app/controllers/users_controller.rb を編集します。

UsersController 変更前
1
2
3
4
5
6
7
8
9
10
11
12
13
def create
@user = User.new(user_params)

respond_to do |format|
if @user.save
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
else
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end

Slack::Notifierに控えておいた Webhook URL を渡して実体化します。
ping関数を実行することで、Slack に通知が飛びます。

UsersController 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def create
@user = User.new(user_params)

notifier = Slack::Notifier.new('Webhook URL')

respond_to do |format|
if @user.save
notifier.ping "user:#{@user.name}が作成されました。"
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
else
notifier.ping "user:#{@user.name}の作成に失敗しました。"
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end

確認

bundle exec rails sで実行し、localhost:3000/usersにアクセスします。

scaffold で作成した時のいつもの画面が見えるはずです。

それでは、アイテムを追加します。

Slack を確認すると、user:#{@user.name}が作成されました。と、コントローラで定義した文字列に、ユーザー名が挿入されて通知されています。

Rails の動作に連携して、Slack に通知できました。


通知の仕方を考える。

通知自体は、データの登録に必要な処理ではありません。
Slack 通知に関して調べていたら、「Sidekiq や Delayed Job を使いましょう」という趣旨の記事にぶつかりました。
通知のために、レスポンスが遅くなってしまう状況は本意でありません。

今回は、github - collectiveidea / delayed_job を導入して通知を試みます。
改修は、github - collectiveidea / delayed_jobを参考に行います。

delayed_job_active_record gem の導入

Gemfile を編集します。

Gemfileに追記
1
gem 'delayed_job_active_record'

編集できたら、bundle installを実行します。

delayed_job を有効化するために以下を実行します。

1
2
bundle exec rails g delayed_job:active_record
bundle exec rails db:migrate

Active Job に登録する

config/application.rb を編集して、config.active_job.queue_adapter = :delayed_jobを書き加えます。

config/application.rb(不要コメントは除去済み)
1
2
3
4
5
6
7
8
9
10
11
12
require_relative 'boot'

require 'rails/all'

Bundler.require(*Rails.groups)

module [アプリケーション名]
class Application < Rails::Application
config.load_defaults 5.2
config.active_job.queue_adapter = :delayed_job ## <=ここに追加
end
end

コントローラを修正

delayed job を使用するように UsersController を編集します。
以下ようは実行を遅延させる処理の手前に.delayをはさみます。

1
2
3
4
5
# Delayed jobを使わない
notifier.ping "user:#{@user.name}が作成されました。"

# Delayed jobを使う
notifier.delay.ping "user:#{@user.name}が作成されました。"

こちらを踏まえてコントローラを修正すると以下のようになります。

UsersController 変更後
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def create
@user = User.new(user_params)

notifier = Slack::Notifier.new('Webhook URL')

respond_to do |format|
if @user.save
notifier.delay.ping "user:#{@user.name}が作成されました。"
format.html { redirect_to @user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: @user }
else
#notifier.ping "user:#{@user.name}の作成に失敗しました。"
notifier.delay.ping "user:#{@user.name}が作成されました。"
format.html { render :new }
format.json { render json: @user.errors, status: :unprocessable_entity }
end
end
end

確認 2

job を実行させるコンソールを別途開いて、アプリケーションと同じディレクトリで、bundle exec rails jobs:workを実行します。
これで job に登録された処理が実行されます。

bundle exec rails sで実行し、ブラウザから再度追加を行います。

追加された後、job 実行用のコンソールを見ると以下のように実行ログが上がっています。

Slack を確認すると、通知が上がっていることを確認できます。
通知されてくるタイミングは Delayed job を使わなかった時と比べて、5 ~ 10 秒くらいラグがありました。


今回は Rails から Slack に通知を飛ばし、関連として Delayed Job を導入してみました。
Slack 通知に関しては、rails と絡めることが前提の gem でもないので、自宅の機器の通知に使うであるとか使い道がたくさんありそうです。
Delayed Job は、ユーザビリティの向上に寄与できそうですし、「やっておいてよかった」を感じました。

ではでは。