知り合いから「Spotifyで流している曲をSlackのチャンネルに投稿してくれるボットが欲しい!」とリクエストをもらい、実際に作って公開してみました。
社内共有として、例えばユーザー登録があった時に通知を出すようなものは何度か実装してきたのですが、公開アプリとして出すのは初めてでした。公開アプリを出すためには、ただアプリを実装するだけでなく、作ったアプリをSlack App Directoryに申請して審査に通過しなければいけません。ここまでやるのが案外大変で、情報も多くなく正直困りました。
「Slackアプリとは!」という点につきましては、ドキュメントや、@muky96rockさんの記事で分かりやすく説明してくれているので、実際にRailsでアプリを実装して、審査に提出してApp Directoryに反映されるまで一連の流れを説明していきます!
できることとしては、Spotify認証をして現在ユーザーが聴いている音楽を取得し、その度にSlackチャンネルに通知を流してくれるアプリ。今のところ、それだけしかできません。ちなみに、今回の記事でSpotify APIの取り扱い部分は省きますが、Webhookの用意がなく、10分おきにAPIを叩きにいってるような仕様にしています。
本当は曲の長さ的に、4分とか、3分おきに取りにいけた方が理想に近いと思うのですが、Heroku Schedulerが10分おきからなので、まあとりあえず無料アプリだしいっかな、とここまでで実装しました。需要があれば、もっと改良します!
登録、実装してSlack App Directoryに公開されるまで
ざっくり、こんな感じで進めていきます。
- Slackアプリを登録する
- Rails アプリを実装する
- Slackアプリを審査に提出する
- Slack App Directoryに公開する
Slackアプリを登録する
大前提として、Slackのワークスペースを持ち合わせておく必要があります。分からないですが、おそらくそのワークスペースが潰れると、そこで作ったSlackアプリも消えてしまうので自分がオーナーとなるワークスペースを用意すると良いでしょう。
APIのページからSlackアプリを作っていきます。後から必要になる準備としてやっておくべきことは下記あたりになります。作りたいアプリによっても変わってくるのですが、今回はユーザーが自分のSlackワークスペースを認証して、チャンネルを選択してそこに通知を送るという仕様を想定しています。
- App Credentialsで
Client ID
と、Client Secret
をメモしておく - PermissionsのOauth部分にリダイレクトURLを追加する
- PermissionsのScopeで
channels:read
とchat:write:bot
を追加する
Railsアプリを実装する
Omniauth認証を実装する
認証のgemで有名なomniauth
を使いました。まずは、ライブラリをインストールして、omniauth.rb
で設定を行ないます。先ほど取得したClient IDと、Client SecretはCredentialsに設定しておきます。
gem 'omniauth'
gem 'omniauth-slack'
Rails.application.config.middleware.use OmniAuth::Builder do
provider :slack,
Rails.application.credentials[:slack][:consumer_id],
Rails.application.credentials[:slack][:consumer_secret],
scope: 'channels:read,chat:write:bot'
end
Sessionコントローラーを用意する
アプリでのログイン/ログアウト周りを実装していきます。Deviseを使うまでもない仕様だったので、今回は自前で作っていきました。Sessionコントローラーと、Userモデルを一緒に用意します。
$ rails g controller sessions new destroy
$ rails g model Users name email provider uid token channel
Userモデルには、Slackのuid、tokenと、channelを保存するカラムを忘れないようにしましょう。fitsy_or_initialize.tap
を使用して、既にユーザーが存在している場合にはそのままセッションを作成し、そうでない場合はユーザーを作成するようにして実装します。
class SessionsController < ApplicationController
def create
user = User.from_omniauth(request.env["omniauth.auth"])
if user.save
session[:user_id] = user.id
redirect_to root_path
else
redirect_to root_path
end
end
def destroy
session[:user_id] = nil
redirect_to root_path
end
end
class User < ApplicationRecord
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_initialize.tap do |user|
user.name = auth.info.name
user.email = auth.info.email
user.token = auth.credentials.token
return user
end
end
end
Rails.application.routes.draw do
get 'auth/:provider/callback', to: 'sessions#create'
get 'auth/failure', to: redirect('/')
get 'signout', to: 'sessions#destroy', as: 'signout'
resources :sessions, only: [:create, :destroy]
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
ここまで作って、http://localhost:3000/auth/slack
で下記のような画面が表示されて、ユーザーが作成されればSlack認証は出来上がったことになります。
slack-ruby-clientをインストール
Slackチャンネルへの通知や、操作にはslack-ruby-client
ができることが多いです。今回も、このライブラリを使って通知を実装していきます。
gem 'slack-ruby-client'
Slack API Clientを作成する
Slackの情報をtokenから取得してくれるモデルを作成します。
class Manager::SlackApiClient
attr_reader :client, :slack_user
def initialize(slack_user)
@slack_user = slack_user
@client = Slack::Web::Client.new(token: slack_user.token)
@client.auth_test
rescue => e
Rails.logger.warn(<<~LOG)
Error @Manager::SlackApiClient#initialize
Msg: #{e.class} #{e.message}
LOG
@client = nil
end
def valid?
client
end
end
チャンネル情報を取得する
通知を受け取るチャンネルをユーザーが選択できるようにします。先ほど作成したAPI Clientのモデルでチャンネル取得を追記。
def channels
client.channels_list.channels
end
Slackチャンネルを選択する画面に合わせて変数を追加します。今回の場合は、Settingsコントローラーを用意していたのでここに記していきます。これでユーザーが認証したワークスペースのチャンネル情報を取得できるはずです。
class SettingsController < ApplicationController
def index
@user = current_user
client_manager = Manager::SlackApiClient.new(@user)
if client_manager.valid?
@slack_channels = client_manager.channels
else
flash[:danger] = 'Slack token expired. Please link Slack app again.'
end
end
end
再生された時に通知を行なう
Spotifyで現在再生されている音楽をSlackに通知します。SpotifyのAPIを叩く部分は今回省きますが(需要があれば別で書きます)、一応、音楽の曲名、URL、アーティスト名、アルバム名をそれぞれ取得して通知するようにしています。
slack_client_manager = Manager::SlackApiClient.new(user)
slack_client_manager.post_song_message(@current_playing) if slack_client_manager.valid?
def post_song_message(song)
attachments = {
text: "🎧 #{song.user.name} is currently playing #{song.name}",
"fields": [
{
"title": "Artist",
"value": song.artist,
"short": true
},
{
"title": "Album",
"value": song.album,
"short": true
},
{
"title": "Spotify url",
"value": song.url,
"short": false
}
],
color: "#f9da00"
}
client.chat_postMessage(channel: "##{slack_user.channel}", attachments: [attachments])
end
通知する部分は、通常のtext
で文言だけ飛ばすこともできるのですが、ちょっと格好良くしたいのであればattachment
を使うのがオススメです。attachmentの装飾方法については、こちらに詳しく書いてあるので参考にしてみてください。
ここまでで一連のSlackに認証して、通知を受けるチャンネルを選択して、実際に通知を受けるところまでの実装が完了したことになります。
Slackアプリを審査に提出する
自前のワークスペースでアプリを使う分にはここまでで問題ないのですが、どのワークスペースにも導入できる公開アプリとして配信するためには、Slackの審査に通過しなくてはいけません。
APIページの、Manage distributionの Distribute app から審査に向けた準備を行っていくことができるようになります。アプリがSlackの利用規約に違反していないか、ちゃんとユーザーにとって有意義なアプリであるかの確認作業がここで行なわれます。基本はチェックボックスを確認していくだけではありますが、他アプリとの連携がある場合はそのログイン情報も提出しなければなりません。今回の場合は、Spotifyのアカウントを作成して記しました。
提出が完了すると、Slack App Directoryの担当者がレビューしてくれるまで待ちます。だいたい4〜5営業日はかかります。そして、結構審査も厳しいです。Slackアプリに関する説明がきちんとランディングページで記載があるかどうか、イメージ画像もそれに準じたものであるかどうかなど、見た目に関するところで3,4回落とされてしまいました。昔はもっと緩かったみたいな話があるので、やはり上場してしまってそのあたり注意が払われているのかもしれないですね。
Slack App Directoryに公開する
審査が通過すると、晴れて公開できるようになります。やっぱり、こういうストア系に自分のアプリが立ち並ぶのはテンション上がります!
さいごに
今年、Slackは晴れてIPOを果たし、日本にもSlack Japanが発足したりと今後社内コミュニケーションとしてSlackが当たり前になる時代が既にきています。今後、SaaSやビジネスツールで勝負するなら、一時期スマホアプリにこぞってみんなが挑戦したように、Slackアプリで勝負をしていくというのも一つありそうだなと思います。
Google Driveや、Trelloのような既存の大きいアプリがSlackで使われるだけでなく、Slackアプリから発足するような例えば、Donutsとか、Lunch Train、Geekbootのようなものも生まれてきています。そのまま世界で使われるような展望も見えるので結構ありですよね!
今回作ったアプリ「OfficeDJ」は本日(11月13日付)でProduct Huntにてレース参加中なので、もしよろしければアップボートしていってください!