Help us understand the problem. What is going on with this article?

Slack アプリをRailsで作って公開するまでの流れ

知り合いから「Spotifyで流している曲をSlackのチャンネルに投稿してくれるボットが欲しい!」とリクエストをもらい、実際に作って公開してみました。

社内共有として、例えばユーザー登録があった時に通知を出すようなものは何度か実装してきたのですが、公開アプリとして出すのは初めてでした。公開アプリを出すためには、ただアプリを実装するだけでなく、作ったアプリをSlack App Directoryに申請して審査に通過しなければいけません。ここまでやるのが案外大変で、情報も多くなく正直困りました。

「Slackアプリとは!」という点につきましては、ドキュメントや、@muky96rockさんの記事で分かりやすく説明してくれているので、実際にRailsでアプリを実装して、審査に提出してApp Directoryに反映されるまで一連の流れを説明していきます!

qiita.png

できることとしては、Spotify認証をして現在ユーザーが聴いている音楽を取得し、その度にSlackチャンネルに通知を流してくれるアプリ。今のところ、それだけしかできません。ちなみに、今回の記事でSpotify APIの取り扱い部分は省きますが、Webhookの用意がなく、10分おきにAPIを叩きにいってるような仕様にしています。

本当は曲の長さ的に、4分とか、3分おきに取りにいけた方が理想に近いと思うのですが、Heroku Schedulerが10分おきからなので、まあとりあえず無料アプリだしいっかな、とここまでで実装しました。需要があれば、もっと改良します!

登録、実装してSlack App Directoryに公開されるまで

ざっくり、こんな感じで進めていきます。

  1. Slackアプリを登録する
  2. Rails アプリを実装する
  3. Slackアプリを審査に提出する
  4. Slack App Directoryに公開する

Slackアプリを登録する

build_slack_app.png

大前提として、Slackのワークスペースを持ち合わせておく必要があります。分からないですが、おそらくそのワークスペースが潰れると、そこで作ったSlackアプリも消えてしまうので自分がオーナーとなるワークスペースを用意すると良いでしょう。

APIのページからSlackアプリを作っていきます。後から必要になる準備としてやっておくべきことは下記あたりになります。作りたいアプリによっても変わってくるのですが、今回はユーザーが自分のSlackワークスペースを認証して、チャンネルを選択してそこに通知を送るという仕様を想定しています。

  • App CredentialsでClient IDと、Client Secretをメモしておく
  • PermissionsのOauth部分にリダイレクトURLを追加する
  • PermissionsのScopeでchannels:readchat:write:botを追加する

Railsアプリを実装する

Omniauth認証を実装する

認証のgemで有名なomniauthを使いました。まずは、ライブラリをインストールして、omniauth.rbで設定を行ないます。先ほど取得したClient IDと、Client SecretはCredentialsに設定しておきます。

Gemfile
gem 'omniauth'
gem 'omniauth-slack'
config/initializers/omniauth.rb
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 を使用して、既にユーザーが存在している場合にはそのままセッションを作成し、そうでない場合はユーザーを作成するようにして実装します。

app/controllers/sessions_controller.rb
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  
app/models/user.rb
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
config/routes.rb
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認証は出来上がったことになります。

build_slack_app_1.png

slack-ruby-clientをインストール

Slackチャンネルへの通知や、操作にはslack-ruby-clientができることが多いです。今回も、このライブラリを使って通知を実装していきます。

Gemfile
gem 'slack-ruby-client'

Slack API Clientを作成する

Slackの情報をtokenから取得してくれるモデルを作成します。

app/models/manager/slack_api_client.rb
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のモデルでチャンネル取得を追記。

app/models/manager/slack_api_client.rb
 def channels
   client.channels_list.channels
 end

Slackチャンネルを選択する画面に合わせて変数を追加します。今回の場合は、Settingsコントローラーを用意していたのでここに記していきます。これでユーザーが認証したワークスペースのチャンネル情報を取得できるはずです。

app/controllers/settings_controller.rb
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、アーティスト名、アルバム名をそれぞれ取得して通知するようにしています。

play_spotify.rb
slack_client_manager = Manager::SlackApiClient.new(user)
slack_client_manager.post_song_message(@current_playing) if slack_client_manager.valid?
app/models/manager/slack_api_client.rb
 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のアカウントを作成して記しました。

build_slack_app_2.png

build_slack_app_3.png

提出が完了すると、Slack App Directoryの担当者がレビューしてくれるまで待ちます。だいたい4〜5営業日はかかります。そして、結構審査も厳しいです。Slackアプリに関する説明がきちんとランディングページで記載があるかどうか、イメージ画像もそれに準じたものであるかどうかなど、見た目に関するところで3,4回落とされてしまいました。昔はもっと緩かったみたいな話があるので、やはり上場してしまってそのあたり注意が払われているのかもしれないですね。

Slack App Directoryに公開する

審査が通過すると、晴れて公開できるようになります。やっぱり、こういうストア系に自分のアプリが立ち並ぶのはテンション上がります!

buildapp.png

さいごに

今年、Slackは晴れてIPOを果たし、日本にもSlack Japanが発足したりと今後社内コミュニケーションとしてSlackが当たり前になる時代が既にきています。今後、SaaSやビジネスツールで勝負するなら、一時期スマホアプリにこぞってみんなが挑戦したように、Slackアプリで勝負をしていくというのも一つありそうだなと思います。

Google Driveや、Trelloのような既存の大きいアプリがSlackで使われるだけでなく、Slackアプリから発足するような例えば、Donutsとか、Lunch Train、Geekbootのようなものも生まれてきています。そのまま世界で使われるような展望も見えるので結構ありですよね!

今回作ったアプリ「OfficeDJ」は本日(11月13日付)でProduct Huntにてレース参加中なので、もしよろしければアップボートしていってください!

OfficeDJ - Share what's currently playing on Spotify to Slack channel | Product Hunt Embed

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした