RailsでSlackAPIを使用してワークスペースにユーザーを作成、作成したユーザーを既存のチャンネルに招待する

## この記事について
RailsでSlackAPIを使用した開発をする機会があったのでやり方のメモとして残しておきます。
画像が多めなため内容を細かく分割しています。ご了承ください。

<strong>なおこの記事は 2022/02 時点での設定方法、画面情報です。<br>Slackの画面に変更がある場合は随時対応が必要になるのでご注意ください。</strong>

### 動作環境
動作環境は以下になります。
gem `slack-ruby-client` は最新のバージョンではないので注意が必要です。

- OS: MacOS(11.6.2, BigSur)
- Ruby: 2.6.6
- Rails: 6.0.3.6
- slack-ruby-client: 0.16.0
- ActiveJob: 6.0.3.6
- rails-dotenv

また事前に以下の準備が必要になります。

- Slackでワークスペースを追加する
- 追加したワークスペースにチャンネルを追加

### この記事で取り上げないこと
- Slack APIを使用するための登録方法
- エラー対応

### この記事でできること
SlackAPIを使用してRailsアプリで以下をできるようにすることが目的です。

1. Slackに登録されているユーザーを探す
1. ユーザーが見つかったら自動的に該当するSlackワークスペース
  1. ユーザー用ののチャンネルを作成する
  1. 作成したチャンネルに追加(招待)する
1. Slackワークスペースに登録されている既存のチャンネルにユーザーを追加(招待)する


### Railsアプリの準備
下記リポジトリに、今回使うRailsアプリを用意しましたのでcloneしてください。

https://github.com/toshi-ue/example-rails-slackapi-invite-channel

README.md の手順にしたがって、環境構築を行ってください。

### SlackAPIでアプリを作成する(Bot用のAPIキーを作成する)
<strong>一般的にAPIキーを作成する場合はサイト上でAPIキーを発行するだけですが、
SlackAPIではアプリを作るという行為が必要になります。</strong>
アプリを作成するとAPIキーが発行されます。

#### SlackAPI登録画面へ
まずは以下にアクセスします。
[Slack API: Applications | Slack](https://api.slack.com/apps)


#### Slackアプリ作成画面移動する
アクセスしたページに `Create New App`のボタンがあるのでクリックします。
[![Image from Gyazo](https://i.gyazo.com/3a764586cf7d4708d98eab5ac1b9e0dc.png)](https://gyazo.com/3a764586cf7d4708d98eab5ac1b9e0dc)

クリックすると以下のダイアログが表示されるので `From scratch` を選択します。
[![Image from Gyazo](https://i.gyazo.com/7c8f072c5571d79b45091b8baa05fd0f.png)](https://gyazo.com/7c8f072c5571d79b45091b8baa05fd0f)

以下のダイアログが表示で `App Name`, `Pick a workspace to develop your app in`が表示されるので、
1. `App Name(必須)`: 好きな名前(今回は`test2`)
2. `Pick a workspace to develop your app in`: 今回開発で使用するworkspace を選択
といった形で入力欄を埋めて`Create App`をクリックします。
[![Image from Gyazo](https://i.gyazo.com/fedbf2dcdd97b28ba07eef60e0163393.png)](https://gyazo.com/fedbf2dcdd97b28ba07eef60e0163393)

`Create App`を実行すると以下の画面が表示されます。
`Bots`という項目があるので選択します。
[![Image from Gyazo](https://i.gyazo.com/8a8b63b070ef018ac20d57f290af9cd5.png)](https://gyazo.com/8a8b63b070ef018ac20d57f290af9cd5)

#### `Review Scopes to Add`を選択
選択すると以下の画面が表示されます。
`Review Scopes to Add`を選択します。
[![Image from Gyazo](https://i.gyazo.com/a6a578e2e86d0b0eac9bed9a6b9abd93.png)](https://gyazo.com/a6a578e2e86d0b0eac9bed9a6b9abd93)


#### `Add an OAuth Scope`をクリック

クリックしたら以下の画面が表示されます。
[![Image from Gyazo](https://i.gyazo.com/013fd06d2233b2544364146fda671572.png)](https://gyazo.com/013fd06d2233b2544364146fda671572)

少し下にスクロールすると`Scopes`という項目があるので`Add an OAuth Scope`をクリックします。
[![Image from Gyazo](https://i.gyazo.com/2b851453bbebc10561926a6adae0efa9.png)](https://gyazo.com/2b851453bbebc10561926a6adae0efa9)

クリックすると以下の選択項目が表示されます。
(文字入力で検索することも可能です)
[![Image from Gyazo](https://i.gyazo.com/2f22ce46ec5a62b0bbd367de5da8fefd.png)](https://gyazo.com/2f22ce46ec5a62b0bbd367de5da8fefd)


#### 必要なScopeを追加する画面の概要
ここで悩むのがどのScopeを追加すればよいかです。
以下の画面の`API methods`のリンクにとべば確認できます([Web API methods | Slack](https://api.slack.com/methods))。
[![Image from Gyazo](https://i.gyazo.com/69433a7e227bf1e1a75a991f26ac0543.png)](https://gyazo.com/69433a7e227bf1e1a75a991f26ac0543)

すると以下のように`Web API methods`一覧と説明が表示されています。
[![Image from Gyazo](https://i.gyazo.com/d808e70f45ea2ed79a1699dde2d5d5e9.png)](https://gyazo.com/d808e70f45ea2ed79a1699dde2d5d5e9)

その中のひとつを選択すると以下のような画面が表示され`Required scopes`の項目の黄色で表示されている内容が必要なScopeになります。
これを前述したページで一つずつ追加していく必要があります。
[![Image from Gyazo](https://i.gyazo.com/70fa6f1bb70156f8eb265103e0efbc9d.png)](https://gyazo.com/70fa6f1bb70156f8eb265103e0efbc9d)
<strong>ちなみに`Legacy bot tokens`のScopeは`2020/05/05`以降は使えなくなっているので使用できません。</strong>


量が多すぎますね...
しかもここでは<strong>説明文での検索ができません(メソッド名での検索しかできない)</strong>。
膨大なドキュメントから該当する項目を見つけて実際に動作するか確認するのは試行錯誤になる可能性があります。

#### 今回使用するMethod, Scope一覧
探すのは大変なのでサクっと使用するMethod, Scopeを列挙します。
列挙したScopeを<strong>前述した画面</strong>で追加してきます。

- Slackに登録されているユーザーを検索
  - Method: [users.lookupByEmail method | Slack](https://api.slack.com/methods/users.lookupByEmail)
  - Scope
      - users:read.email
      - users:read
- ワークスペースにチャンネルを作成する
  - Method: [conversations.create method | Slack](https://api.slack.com/methods/conversations.create)
  - Scope
      - channels:manage
      - groups:write
      - im:write
      - mpim:write
- ユーザーをチャンネルに追加する(招待する)
  - Method: [conversations.invite method | Slack](https://api.slack.com/methods/conversations.invite)
  - Scope
      - channels:manage
      - groups:write
      - im:write
      - mpim:write
- Slackワークスペースに登録されている既存のチャンネルにユーザーを追加(招待)する
  - Method: [conversations.invite method | Slack](https://api.slack.com/methods/conversations.invite)
  - Scope
      - channels:manage
      - groups:write
      - im:write
      - mpim:write

#### ワークスペースにアプリを追加
Scopeの追加が完了したら以下の画面のように今まで押せなかった`Install to Workspace`ボタンが選択できるようになっているので選択します。
[![Image from Gyazo](https://i.gyazo.com/628b31ffcfa7bbb38b045114ea4be96e.png)](https://gyazo.com/628b31ffcfa7bbb38b045114ea4be96e)

選択すると以下のような画面が表示されます。
内容が同じであればOKです。
`許可する`を選択します。
[![Image from Gyazo](https://i.gyazo.com/dc3006e7e6480934e13afc203f8dc194.png)](https://gyazo.com/dc3006e7e6480934e13afc203f8dc194)

#### APIキー発行完了
以下の画面にページ遷移して`xoxb`からはじまるトークンが表示されていればAPIキーが作成できた形になります。
[![Image from Gyazo](https://i.gyazo.com/718d67316e6b3ca0dfd6ddf3342aabb3.png)](https://gyazo.com/718d67316e6b3ca0dfd6ddf3342aabb3)

#### ワークスペースのチャンネルにアプリを招待(追加)する
以下の手順をそのまま実行してください。
[Slack APIを使ってみよう！【Slack + Rails】 - Qiita](https://qiita.com/murakami-mm/items/c34af59fdff198161967#%E3%83%AF%E3%83%BC%E3%82%AF%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%81%AE%E3%83%81%E3%83%A3%E3%83%B3%E3%83%8D%E3%83%AB%E3%81%AB%E3%82%A2%E3%83%97%E3%83%AA%E3%82%92%E6%8B%9B%E5%BE%85%E3%81%99%E3%82%8B)

### Railsアプリにコードを追加
ActiveJobを使用してバックグラウンドでSlackAPIを使用してユーザーをチャンネルに追加します。

#### 前置き
普通は`rails-dotenv`を使用してAPIキーを管理します。
<strong>ただ今回はわかりやすさのためにあえて直書きします。</strong>
必要な場合は適宜置き換えてください。



#### APIキーを登録する
以下はgem `slack-ruby-client` のGitHubリンクです。
以下に従ってSlackのAPIを使用できるようにします。
[slack-ruby/slack-ruby-client: A Ruby and command-line client for the Slack Web, Real Time Messaging and Event APIs.](https://github.com/slack-ruby/slack-ruby-client)

`config/initializers/slack_ruby_client.rb`を追加して以下を追記します([Using the Legacy API Token](https://github.com/slack-ruby/slack-ruby-client#using-the-legacy-api-token))。

```ruby:config/initializers/slack_ruby_client.rb
Slack.configure do |config|
  config.token = 'xoxb-xxxxxxxxxxxxxxxx'
  # config.token = ENV['BOT_USER_ACCESS_TOKEN']
end
```

#### ActiveJobを使用してバックグラウンドで処理させるためのコードを追加する
`app/controllers/users_controller.rb`に以下のコードを追記します。

```ruby:app/controllers/users_controller.rb
  # POST /users or /users.json
  def create
    @user = User.new(user_params)

    respond_to do |format|
      if @user.save
        # 追記開始
        SlackJob.perform_later(user.email, user.channel_name)
        # 追記終了
        format.html { redirect_to user_url(@user), notice: "User was successfully created." }
        format.json { render :show, status: :created, location: @user }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @user.errors, status: :unprocessable_entity }
      end
    end
  end
```

#### `slack-ruby-client`で使用できるメソッドを探す
ここはとても重要です。
理由としては以下が挙げられます。

- SlackAPIでアプリの登録ができても`slack-ruby-client`で該当するメソッドを見つけられなければ意味がない
- `slack-ruby-client`のgemが最新ではない(最新は1.0.0、プロジェクトのgemのバージョンは `0.16.0`)

全てに該当するわけではないですが今回は以下のリンクからメソッドを見つけてきました。
[File: README — Documentation for slack-ruby-client (0.16.0)](https://www.rubydoc.info/gems/slack-ruby-client/0.16.0)
注意したいのは<strong>`gemのバージョンがあっているかどうか`</strong>です。
プロジェクトによって使用しているgemのバージョンは違いますし、それによってメソッドの有無、挙動も変わってくる可能性があるからです。

該当するメソッドはググっても該当する内容が一発で見つかりませんでした。
RubyDocで該当するgemを見つけても該当するメソッドを見つけるのが大変でした。
今回は以下の手順で見つかりました。

- `slack-ruby-client 0.16.0`で検索(該当するバージョンのgemのRubyDocのページへ入る)
- `search`フォームの上のメソッドをクリック
- クリックしてメソッドが一覧表示されるので一番上のメソッドをクリック
1. SlackAPIのページで同じ名前のメソッドがあるか検索（あるはずです）
1. RubyDocとSlackAPIの同じメソッドを比較
1. 該当するメソッドを見つける(slackAPIでの`.`がslack-ruby-clientのメソッド名の`_`に該当する)

見つけるのにとても時間がかかりました。全文検索入れて欲しい...

#### ActiveJobのコードを追加
`app/jobs/slack_job.rb`を作成して以下のコードを追記します。

```ruby:app/jobs/slack_job.rb
# frozen_string_literal: true

class SlackJob < ApplicationJob
  queue_as :default

  def perform(email, channel_name)
    # https://github.com/slack-ruby/slack-ruby-client#web-client
    client = Slack::Web::Client.new
    client.auth_test

    # ユーザーを検索
    # https://www.rubydoc.info/gems/slack-ruby-client/0.16.0/Slack/Web/Api/Endpoints/Users#users_lookupByEmail-instance_method
    user = client.users_lookupByEmail(email: email)
    # Slackのユーザーidを取得
    user_id = user.channel.id

    # ユーザー用のチャンネルを該当のワークスペースに追加
    # https://www.rubydoc.info/gems/slack-ruby-client/0.16.0/Slack/Web/Api/Endpoints/Conversations#conversations_create-instance_method
    client.conversations_create(name: channel_name)

    # ユーザーを招待したいチャンネルのidを定義
    slack_should_be_invited_channel_id = 'SLACK_CHANNEL_ID_1'
    # slack_shouldable_channel = ENV['SLACK_CHANNEL_ID_1']
    # 複数の場合は以下のように設定すれば良い
    # slack_shouldable_channel_ids = ['SLACK_CHANNEL_ID_1', 'SLACK_CHANNEL_ID_2']

    # https://www.rubydoc.info/gems/slack-ruby-client/0.16.0/Slack/Web/Api/Endpoints/Conversations#conversations_invite-instance_method
    client.conversations_invite(channel: slack_should_be_invited_channel_id, users: user_id)
    # 複数のチャンネルに登録する場合
    # slack_shouldable_channel_ids.each do |slack_shouldable_channel_id|
    #   client.conversations_invite(channel: slack_shouldable_channel_id, users: user_id)
    # end
  end
end

```

#### (補足)ActiveJobでのバックグラウンドの動作確認について
ActiveJobなどのバックグラウンドの処理はterminal上には表示されません。
確認するには`log/development`ファイルを開いて確認することができます。

### 参考にしたサイト
[Slack APIを使ってみよう！【Slack + Rails】 - Qiita](https://qiita.com/murakami-mm/items/c34af59fdff198161967)
[RailsプロジェクトでSlack通知を実装する ｜ もふもふ技術部](https://tech.mof-mof.co.jp/blog/rails-slack-notifier/)
[環境変数で配列もハッシュも扱いたい - Qiita](https://qiita.com/rh_taro/items/70bd1680c31d94db13b7#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E3%83%91%E3%83%BC%E3%82%B9%E3%81%97%E3%81%A6%E4%BD%BF%E3%81%86)