PostgreSQL Tips

Ruby × PostgreSQLまわりで使いそうなコマンドを自分用にまとめておく。

(随時更新予定)

# バージョン確認
postgres -V

# デフォルトのデータベースに接続
psql -d postgres

# 直接データベースに接続
psql -d テーブル名

# データベースの選択
\c データベース名

# データベース一覧確認(psqlコマンドで)
psql -l

# データベース一覧確認(プロンプト上)
\l

# SQLでデータベース一覧確認
SELECT * FROM pg_database;

# テーブル一覧確認
\dt

# テーブル構造の確認(シーケンステーブルなども表示)
\d

# 外部ファイルのSQLを実行
\i ファイル名

Minitest Tips

Minitestで各テストの最初、最後、全てのテストの最後に実行したい処理は次のように書ける。

require 'minitest/autorun'

class XxxTest < Minitest::Test

  # 全てのテストが終わった後に処理される
  Minitest.after_run do
    p "after_run"
  end

  # 各テストの最初に実行される
  def setup
    p "setup"
  end

  # 各テストの最後に実行される
  def teardown
    p "teardown"
  end

  def test_xxx
    ...
  end

  def test_xxx
    ...
  end
end

実行結果

% bundle exec ruby test/xxx_test.rb
Run options: --seed 26197

# Running:

"setup"
"teardown"
."setup"
"teardown"
.

Finished in 0.026552s, 112.9858 runs/s, 37.6619 assertions/s.

2 runs, 1 assertions, 0 failures, 0 errors, 0 skips
"after_run"

フィヨルドブートキャンプに入会してから休会までの3ヶ月報

都合によりフィヨルドブートキャンプを休会することになったので、始めてからの3ヶ月間の3ヶ月報的なものを簡単にまとめておこうと思います。

目次

フィヨルドブートキャンプ歴

  • 2020/12月末:育休中に3日間のお試し後、一旦休会
  • 2021/4月末:仕事復帰と共にフィヨルドブートキャンプにも復帰
  • 2021/7月末:都合により再び休会

ちなみに今回の休会理由は旦那さんの資格取得の勉強があり、しばらくは土日に家事や育児を頼めなくなってしまったためです。

フィヨルドブートキャンプを始めた経緯や感想などはこちらに書いています。

フィヨルドブートキャンプに参加して2ヶ月経過 - mashym blog

3ヶ月でやったこと

ラクティス

フィヨルドブートキャンプの学習内容はこちらを参照。

学習内容 | FJORD BOOT CAMP(フィヨルドブートキャンプ)

  • HTML&CSS

    • 現在は「発展編」に移動してしまいましたが、以前は「HTML&CSS」のカテゴリにあったCSS上級の課題はかなり難易度が高くCSSを改めてしっかり学べました。
  • Vi

  • Linux
    • Unixコマンドや「標準入出力・リダイレクション・パイプ」などLinuxまわりはちゃんと学習しておいて損はないですね。
    • 「新しいLinuxの教科書」や「シス管系女子」なども学びが多かったです。
  • Git & GitHub
    • 仕事ではGUIツールを使っていましたが改めてgitコマンドを学習して、コマンドでほとんど操作できるようになってきました。
  • Ruby
    • カレンダープログラムやlsコマンド、wcコマンドをRubyで自作するのですが、プルリクをしてメンターの方にレビューしてもらえるのでGithubでのやりとりの勉強にもなります。
    • 課題完了後に他の生徒の方の成果物が見られるのですが、自分のコードと全然違ったりして面白いです。他の人のコードをたくさん読めるのもフィヨルドブートキャンプの良さです。
  • HTTP
  • Nginx
    • Nginxをちゃんと自分で触ったり設定したことがなかったので、基本が学べて良かったです。
  • データベース
    • 普段MySQLを使っているのでSQLやDB設計の基本的な部分は問題なく理解できました。
    • フィヨルドブートキャンプではPostgreSQLを使っているので、今後こちらをしっかり学んでいけたらと思います。
  • Webアプリケーション
    • 「Webを支える技術」を読んで改めてRESTの考え方が理解が深まった気がします。
    • Sinatrahttp://sinatrarb.com/)で簡単なWebアプリを作成する課題があるのですが、動くものを作るのはやはり面白いなと感じました。(早くRailsやっていきたい)
    • 上記課題を提出して、「WebアプリからのDB利用」の途中まで進めたところで休会となりました。

読書

3ヶ月間で読んだ本です。今までは3ヶ月とかでこんなに本を読んだことなかったんですが、毎日時間を見つけてちょこちょこ読む習慣が少しついた気がします。

  • 新しいLinuxの教科書
  • シス管系女子1
  • シス管系女子2(途中)
  • ゼロからわかるRuby超入門
  • プロを目指す人のためのRuby入門
  • Webを支える技術
  • この一冊で全部わかるWeb技術の基本(ざーっと)
  • 達人プログラマ 熟達に向けたあなたの旅(途中)
  • 楽々ERDレッスン

感想

フィヨルドブートキャンプでは学習した日は基本的に日報を書いて提出するようになっているので、その日にやったことや学び、自分の気持ちなどを文字に起こすことで、何を理解して何を理解できていないのか整理する力がつくと思います。 これは質問をするにも大事な要素(何がわかって何がわからないのかを伝える力)なので、ただプラクティスを進めるのではなくきちんと日報にまとめられると仕事でも活きてくる部分かなと思いました。 あとは以下の部分をもう少し意識していけたらと思います。

  • 短い時間でまとめる。
  • あとで見返したときや、他の人が見たときに役に立つ(わかりやすい)ようにまとめる。

3ヶ月で50%ちょっとプラクティスを完了したところですが、学習時間の捻出がなかなか大変だったので時間が取れる方や経験者の方ならもっと短期間で進められると思います。

日報もそうですが、Discordで他の生徒の方の進み具合や、つまづいた点、わかった事、わからない事、今の気持ちや人柄など本当にいろいろな事が読み取れたり知れたりして励みにもなります。 あまり積極的に絡んでいっていたわけではないのですが、Discordでの分報チャンネル(今やっていることや気持ちをつぶやく自分専用チャンネル)での発言にリアクションや返信をもらえるだけでもモチベーションがあがりました。

復帰後はより積極的に活用していけたらと思います。

今後の予定と目標

とりあえず10月後半か11月の復帰を目指していて、それまでは今までに購入した学習本を読み返したり、アウトプットや他のコミュニティへの参加など時間があればやっていきたいなと思っています。

復帰後は自作サービスのリリースあたりまでを目標にしていますが、プラクティスを通してエンジニアとしてレベルアップできるようにコツコツ頑張っていきたいです!

git rebaseとgit mergeの違いを確認する

f:id:mashym91:20210730205537p:plain 今までgitでのブランチ統合は 「git merge」しか使ったことがなく、「git rebase」に対して「コンフリクトしたら面倒」というイメージがあり、ほぼ使ったことがありませんでした。 rebaseの方が履歴がキレイになるというのは認識していましたが、mergeで特に困っていなかったというのもあります。

ただ最近はフィヨルドブートキャンプでgitを基礎から学んでいることもあり、今まであまり使っていないgit操作も気になったら自分のテスト用のリポジトリで挙動を確認するようにしています。 サッとテストできるようにしておくといざミスったときに、『このコマンド実行したらできそうだけど、間違えたらどうしよう』というのが解消されたりするのでおすすめです。

とにかく試してみればわかる

以下のようなケースで試してみました。

ケース

  • mainブランチから開発ブランチ(今回はrebase_testブランチ)を切る
  • rebase_testブランチへの追加開発用にrebase_test2rebase_test3ブランチを切る
  • それぞれ変更を加えた後、先にrebase_test2の変更がpushして、rebase_testにプルリク、マージされた状態。

やりたいこと

  • rebase_test3はまだローカルにのみ存在していてpushしていないので、rebase_test2の変更を取り込みつつ「rebase」を使って履歴はなるべくキレイに保ちたい。

補足

  • rebaseとmergeの違いを確認したいので、今回はgit checkout -b rebase_test3_backuprebase_test3のコピーをとっておく。 

rebase/merge前の状態

''
rebase_test2をrebase_testにマージしたgitログ

rebaseした場合

// rebase_testにrebase_test2のマージをpull済みの状態
$ git switch rebase_test3
$ git rebase rebase_test

rebase_test3をrebase_testにリベースしたgitログ

コミット番号が変わるが、ログ履歴がキレイになっている。(rebase_testとrebase_test3が一本化されている)

mergeした場合

// rebase_testにrebase_test2のマージをpull済みの状態
// rebase_test3のコピーブランチrebase_test3_backupで確認する
$ git switch rebase_test3_backup
$ git merge rebase_test

マージのコミットメッセージを編集してコミット

rebase_test3_backupをrebase_testにマージする際のコミットメッセージ

rebase_test3_backupをrebase_testにマージしたgitログ

コミット番号は変わっていないが、履歴が複雑。+マージコミットができている。

まとめ

今回やってみてrebaseの動きやmergeとの違いが改めてわかったので、ローカル作業では分岐元のブランチにリベースして履歴をキレイにして、pushするようにしていきたいなと思いました。チーム開発などでは方針にもよると思いますが、push済みのブランチに関してはいつどこでブランチ統合されたのかなど履歴を追えるmergeの方が適しているのかなと個人的には思ったり。あとrebaseをすると処理が作り直される(コミット番号が変わる)ので、チーム開発で既に参照されてるものをrebaseしてしまうと壊れてしまうのであまりやらない方がいいというのもありますね。

あとはこまめにcommitとpushをするようにするのが大事ですね。変更が多いほどコンフリクトが発生する可能性は高くなるので。

参考

フィヨルドブートキャンプに参加して2ヶ月経過

4月末からフィヨルドブートキャンプに参加していて2ヶ月ほど経ったので、感想や進捗をまとめてみました。 本当は50日目あたりのキリの良いときに出したかったところですが、あっという間に過ぎ去り微妙なブログタイトルになりましたw

目次

軽く自己紹介

mashym(マッシュ)です。最近読み方を決めました。 現在Web系エンジニアをしていて仕事でもRuby on Railsを使っています。 2021年4月まで育休をとっており、4月から仕事復帰したところです。と同時にフィヨルドブートキャンプでの学習もスタートさせました。 育児と仕事と学習の三刀流を目指して頑張っています。

フィヨルドブートキャンプとは

プログラマーとして就職を目指せるだけのスキルを身につけることを目標としたオンラインプログラミングスクールです。就職を目指せるスキルを弊社では「現場の人間にとって、戦力になるプログラマー」としています。具体的には、一人でWebサービスを作ることをゴールとした課題をやるのですが、それだけでなくチーム開発も経験できます。

FJORD BOOT CAMP(フィヨルドブートキャンプ)

スクールの経緯についてはこちらに町田さんの「大江戸Ruby会議08」での資料がありました。有料化したのは2019年5月〜でわりと最近なんですね。この記事で知りました。

プログラミングスクールを始めた経緯とこれからの話 - Speaker Deck

フィヨルドブートキャンプでは「メンター」という現役プログラマの方々がコードレビューや日報チェック、質問への回答などさまざまなことをアドバイスしてくれます。 メンターについては伊藤さんのこちらの記事に詳しく載っています。 伊藤さんをはじめ、Ruby界隈やIT業界で有名な方も多く在籍しているので、そのコミュニティに入れているだけでかなり貴重な経験な気がします。

フィヨルドブートキャンプのメンターとしてやっていること、感じていること #fjordbootcamp - give IT a try

始めようと思った経緯

IT業界に未経験(ほぼ何もわからない状態)で中途で入り、基礎がないままにとりあえずコードを書いて動くものを作っていく中でなんとか仕事はこなしてはきましたが、なにか課題にぶつかると自己解決できない、解決方法がわからないという事が多々あり、そこからの成長が自分でもなかなかできずずっとモヤモヤしていました。(正確には課題を自己解決できないことが問題というより、解決した後でその原因や解決方法を振り返り、身につけて来れなかったことが成長できていない要因だと今は思っています。)

いろいろな言語を少しずつかじって深く学んでこなかったこともあり、人にきちんと説明できるほどの知識や技術があまりないというのもコンプレックスで、時間だけが経過して新人という期間をあっという間に過ぎ、初歩的な質問をするのが恥ずかしくなって放置しがちになるという典型的なダメエンジニアとなっていました。

「自走する」というキーワードを最近よく聞きますが、自分は自走しないエンジニアになりつつあるように感じていてどうにかしたいという思いが年々強くなっていました。ちゃんと勉強したいと思いつつ確保できる時間も少ない中で何をどこからやったらいいのか、いろいろ調べていたときにフィヨルドブートキャンプの生徒さんのブログを読んでフィヨルドブートキャンプの存在を知りました。そこからはフィヨルドブートキャンプのサイトや関連記事を読んで「やってみたい!」という気持ちがすぐに強くなり、育休中の昨年末に「3日間のお試しをやりたい」と、旦那さんに相談してその3日間はできるだけ学習に専念できるように協力してもらいました。

理由についてはかなりネガティブ面を強調して書いてはいますが、過小評価な部分もあるとは思います😅 でも要は「わからないことをちゃんとわからないと言って学びたい!」「自走したい」と思ったので入会しました。

ちなみに転職希望は今のところないです。エンジニアとしてもっと成長したいというのが当面の目標です。

フィヨルドブートキャンプを始めてみて

お試し期間

上記のとおり育休中に旦那さんに協力してもらって、お試し期間の3日間みっちりやってフィヨルドブートキャンプが自分に合っているか確認しました。Slack(現在はDiscord)での気軽なやりとりやプラクティスの充実さを感じて引き続きやっていきたいと思えたので、お試し期間で一度退会して、育休後に復帰させてもらいました。

フィヨルドブートキャンプは一時的に退会しても連絡をすれば学習の続きから再開することが可能です。

学習時間と進捗

お試し期間分があるので学習開始からは現在180日を超えていますが、3-4ヶ月の退会期間があるので実質的には60日超えたくらいで、合計学習時間は現在229.3時間です。 ちなみに卒業までには900時間くらいかかるとあるので4分の1程度終わってるイメージでいいかもしれません。プラクティス的な進捗でいうと現在50%を少し超えたところです。

mashymのフィヨルドブートキャンプ学習時間
学習時間

主な学習時間帯

旦那さんの協力があるかないかで学習時間の確保が大きく変わってくるので、協力してもらえる日はとても助かります。

平日

詳細は以下ですが、平日は1〜3時間ほど確保できているかなという感じです。

  • 旦那さんが保育園の送迎や育児をしてくれる場合

    • 朝8時ごろ〜仕事を始める9時ごろまで(フレックスのためこの辺は変動しますが30分〜1時間弱)
    • 17、18時〜19時半ごろまで
  • 自分が保育園の送迎や育児をする場合

    • 保育園に送っていって仕事が始まるまでの15〜30分ほど
    • 仕事終わり〜保育園お迎えまでの15〜30分ほど
  • 共通

    • お昼休み。30分ほどで食事と休憩をとって残り30分ほどで学習(ここは元気があればで、疲れていたら全部寝てしまいますw)
    • 夕飯、家事が終わった21、22時ごろ〜23時ごろまで

週末

旦那さんが予定がない限りはかなり家事や育児をしてくれるので日によりますが4〜6時間確保できている気がします。(ただただ感謝✨)

家族との時間を削ればもう少し学習にあてられる気はしますが、それは本末転倒な気もするので今はこれが精一杯かなと思っています。

ラクティスを進めてみての感想

フィヨルドブートキャンプでは転職を目標としている方や、自分のような現役のエンジニアさん、学生さんに子育てをしながらの方などいろんな方が頑張っています。 Discordでコミュニケーションをとったり、他の人の日報も自由に見れるので、進捗やどんな取り組み方をしているのかがわかり、身近に感じることもありとても励みになります。

雑談部屋や質問チャンネルがあったり学習本の輪読会が定期的に開かれていたり、コミュニケーションの場、質問の場は多いのでこれらをフル活用できるとすれば月額3万は高くないと思います。 自分は学習時間が不定期なところもあってまだ全然フル活用できていませんが。。 でもフィヨルドブートキャンプで学ぶことは自分の将来への投資と考えているので月額3万は決して安くはないけど高くもないという考えです。お金の面で言うとプラクティスに必要な書籍代もけっこうかかってはきますが(一気にではなく随時)、こちらも投資の一貫と考えています。

知識への投資は常に最高の利息がついてくる

ベンジャミン・フランクリン

もともと学ぶことは嫌いではないのと、やるとなったらイチからきっちりやりたいタイプではあるので体系的なカリキュラムを順を追って学習していけるのはとても自分に合っているように思います。基礎からやって今まで見逃していたり、そもそも知らなかったことが知れるとさらに学習が楽しくなってきます。

自分は初心者・未経験ではないので、イメージ的にはいくつもの点がすでに散りばめられている状態だと思います。プラクティスを通してそれらを線でつないで理解を深め、探求して点や線を大きく太くしていけたらと思っています。

また、生徒さんには経験者、未経験者さまざまな方がいて、カリキュラムの内容は決して簡単なものばかりではないですが、わからないことを質問したり不明点を確認したりといったメンターの方とのやりとりは実際の仕事に通ずるものがあるので、経験の有無よりもそれらのやり方を学び実践できるかが成長の鍵のような気がします。「良い質問の仕方」ができるかはそれだけで一冊の本になるほどエンジニアに関わらず重要なスキルですが、フィヨルドブートキャンプでもその点はかなり強調されているように思います。

質問は恥ではないし役に立つ - Qiita

すんなりプラクティスを完了してしまうよりも、一つでも疑問点をもって調べたり、質問したりしてプラクティスを完了した方がプラスになる気がするので、今後もその点は意識していきたいところです。(意識はしててもまだあまり実践できていないのでこれからですがw)

大変な点

育児、仕事をしながらの学習はやはり大変です。仕事終えてそのままプラクティスの勉強をしてると目が血走ってますw 休みの日に子供と遊んであげたいのにそーっと部屋に籠もる時は「ごめんね」という気持ちでいっぱいです。

育児に限らず皆さんいろいろ抱えながらいろんな思いで参加していると思うので、あまり言い訳にはしたくない部分ではありますが、それでも2ヶ月間やってこられているのはフィヨルドブートキャンプを「楽しい!」と感じられているからだと思います。育児しながらの生徒さんメンターの方も多いのでDiscordでは共感できるつぶやきも多いですし、自分も頑張ろうという気持ちにすごくなります。何より旦那さんの協力や理解がなければまずできていないので有り難い限りです。

どういうエンジニアになりたいか

  • 自走できるエンジニア

与えられたことだけをやるのではなく、自ら深堀りして学び、経験値を増やして共有したりアウトプットまでしていけるようになりたいです。

  • プログラミングが楽しめるエンジニア

正直、育休前までは仕事をただこなしているという感覚でした。でもやっぱり深く知って楽しいと感じられるようになりたいです。仕事にする以上楽しいだけではやっていけないですが、問題が解決したときや新しい知識がついたとき、開発が完了したとき、使ってもらって良い反応があったときなどは嬉しい、楽しいと感じるのでその気持ちを大切にしたいです。

今後の課題

  • わからない点を納得いくまで調べる
  • 調べてわからなかったら整理して質問する
  • わかったこと、思ったことをアウトプットする(ブログ、Twitter、Discordなど)

最後に

フィヨルドブートキャンプの良さはコミュニティにある気がします。先程も言ったとおり自分はまだ全然活用できていませんが、輪読会へのラジオ参加(ミュートにして他の人の会話を聞くだけ)や質問や雑談のやりとりを見たり聞いたりするだけで一人で独学するのとは違ったメンタルになります。 基本的には一人で学習していくわけですが、イメージとしては友達や家族、身近な人が何かを頑張っていると自分も頑張ろうと思える気持ちに似ているかもしれません。

これからプラクティスの難易度も上がってくると思いますが、コミュニティを活かしつつ他の生徒さんの頑張りやメンターの方からのアドバイスを糧に頑張っていきたいです。

sedの後方参照を使った置換を理解する

シス管系女子2の第7話に出てくる sedコマンドの「後方参照」がいまいち理解できなかったので調べてみました。

sedコマンドとは

「Stream EDitor」の略で、「sed スクリプトコマンド ファイル名」で、指定したファイルをコマンドに従って処理し、標準出力へ出力します。ファイル名を省略した場合は、標準入力からのデータを処理します。sedコマンドでは、パイプとリダイレクトを活用するのが一般的です。

【 sed 】コマンド(基礎編)――テキストファイルを編集する:Linux基本コマンドTips(53) - @IT

vimなどのような対話型エディタではなく、コマンドラインのオプションのみで指示。 流れてくるテキストを編集するから「ストリーム(流れの)エディタ」と言います。

主に文字列の置換、抽出、削除などの処理に使われるコマンド。 ちなみにsedコマンドは編集結果を標準出力に出力するので元のファイルは変更しないので、パイプやリダイレクトを組み合わせて使われることが多いです。

置換

後方参照の前にsedコマンドでよく使われる通常の置換処理についてまとめておきます。(細かい話は省略して簡単にまとめます。)

例) sed_test.txtの内容

ABC
ABCABC
ABCABCABC
  • 行頭に出てくる文字列だけ置換

sed "s/置換前/置換後/" ファイル名

$ sed "s/ABC/DEF/" sed_test.txt
DEF
DEFABC
DEFABCABC
  • すべての文字列を置換する場合は末尾にgを付ける

sed "s/置換前/置換後/g" ファイル名

$ sed "s/ABC/DEF/g" sed_test.txt
DEF
DEFDEF
DEFDEFDEF

ちなみにcatコマンドと |パイプラインでつなげてsedコマンドを使っても同じです。

$ cat sed_test.txt | sed "s/ABC/DEF/g"

後方参照

本題で、これは置換前の内容を置換後に引用させるためのものです。 例えばABCの部分を後ろにDEFを付けてABCDEFとしたい場合などに使えます。 具体的にどうするかというと、

  • 引用したい部分を( )で囲む。(拡張正規表現-rオプションを付ける)
    • -rオプションを付けない場合は\(\)で囲んでエスケープすればいいが可読性が少し悪くなる。
  • そうすると、( )で囲った部分を順に\1 \2で参照することができる。
    • ( )が1つなら\1のみ、2つなら\1 \2、3つなら\1 \2 \3...で参照可。
$ sed -r "s/(ABC)/\1DEF/g" sed_test.txt
ABCDEF
ABCDEFABCDEF
ABCDEFABCDEFABCDEF

2箇所参照の場合

$ sed -r "s/(A)(B)/\1D\2E/g" sed_test.txt
ADBEC
ADBECADBEC
ADBECADBECADBEC

上記はAが\1、Bが\2で参照できるようになって、ABC→ADBECと置換されている。

後方参照の理解は少し難易度が高いですが、( )で囲った部分を引用という事がわかれば理解しやすそうです。

slack API + GASでリアクションがあったら指定チャンネルにメンション通知する

まえがき

Slackでリアクションされたら、メンション&リアクションに一覧表示されますが、リアルタイムでリアクションに気づきたくて通知されるようにSlack API+GASで実装してみました。

というのも夫婦間でSlackを使っていて、家事育児をしていると仕事中のように常にSlackを開いているわけではないのでリアクション通知があったらいいなという気持ちで作ってみました。

こんな通知がくるようにしました。

通知イメージ

ちなみにメンバーが多いと通知がきまくってうざいので、メンバー2人ならではの機能だとは思います。

構成

構成図

  • Slackのリアクションイベントをトリガー
  • GASでPOSTリクエストを受け取って処理
  • GASからIncoming WebhooksでSlackの対象チャンネルにメッセージ投稿

*GASとGitHub連携はGoogle Apps Script GitHub アシスタントを使っています。

実装

GAS作成(公開)

サーバ側はGASで用意しました。 「ウェブアプリ」としてデプロイして、公開URLをメモしておきます。

Promise.allを使ってチャンネル名とユーザIDを取得しておいて、Webhookで「リアクション+メンション+メッセージURL」を対象チャンネルに投稿するようにしています。

const props = PropertiesService.getScriptProperties().getProperties();
const oAuthAccessToken = props.OAUTH_ACCESS_TOKEN;
const slackApiBase = 'https://slack.com/api/';

function doPost(e){
  const json = JSON.parse(e.postData.getDataAsString());
  const itemChannel = json.event.item.channel;
  const itemTs = json.event.item.ts;
  const reaction = json.event.reaction;

  Promise.all([
    fetchChannel(itemChannel),
    fetchMessage(itemChannel, itemTs)
  ])
  .then(function(data) {
    const [channelName, messageData] = data;
    const message = "<@" + messageData["userId"] + ">" + "[" + channelName + "]にリアクションがつきました。\n\n" + messageData["linkUrl"];
    const jsonData = { "text": ":" +reaction + ":" + message };
    const payload = JSON.stringify(jsonData);
    const options = {
      "method" : "post",
      "contentType" : "application/json",
      "payload" : payload
    };

    UrlFetchApp.fetch(props.WEBHOOK_URL, options);
  })
  .then(() => {
    return ContentService.createTextOutput(params.challenge);
  })
}

// チャンネルリストを取得してチャンネルIDから対象のチャンネル名を取得
function fetchChannel(channelId) {
  return new Promise((resolve) => {
    const channelsUrl = slackApiBase + 'conversations.list?token=' + oAuthAccessToken + '&exclude_archived=1&pretty=1';
    const channels = JSON.parse(UrlFetchApp.fetch(channelsUrl)).channels;
    const targetChannel = channels.find(channel => channel.id === channelId);
    const channelName = (targetChannel !== undefined) ? targetChannel.name : "チャンネル以外";
    resolve(channelName);
  })
}

// メンション用に対象メッセージ投稿者のユーザIDを取得
function fetchMessage(channel, ts) {
  return new Promise((resolve) => {
    const url = slackApiBase + "conversations.replies?token=" + oAuthAccessToken + "&channel=" + channel + "&ts=" + ts + "&latest=" + ts + "&limit=1&inclusive=true" 
    const replies = JSON.parse(UrlFetchApp.fetch(url));
    const targetMessage = replies.messages[0];
    const isThread = (targetMessage.thread_ts !== undefined && targetMessage.ts !== targetMessage.thread_ts);
    let linkUrl = props.SLACK_WORKSPACE_URL + "archives/" + channel +"/p" + String(targetMessage.ts).replace(/\./g, '');
    // スレッドの場合
    if(isThread) {
      linkUrl += "?thread_ts=" + String(targetMessage.thread_ts).replace(/\./g, '') + "&cid=" + channel;
    }
    resolve({linkUrl: linkUrl, userId: targetMessage.user});
  })
}

参考

qiita.com

環境変数

GASのプロパティストアを利用。

  • OAUTH_ACCESS_TOKENはSlackアプリ作成時のOAuth & Permissions > Scopes設定後に表示されるものを定義します。

  • WEBHOOK_URLはSlackアプリ作成時にIncoming WebhooksONにしてURLを取得します。投稿先は#reactionチャンネルを作成して設定しました。

IDEではなぜかプロパティ編集画面がなくなっていてかなりつまづきました。 仕方ないのでプロパティストアの設定時だけ旧IDEに戻して設定後にまた新IDEに戻しました。

プロパティストア

ちなみに旧IDEに戻す際に以下のようなアンケートが出たのでMissing script property editingにチェックしておきましたw

f:id:mashym91:20210220175144p:plain:w300

Slackアプリ作成

Slackアプリの作成はこちらを参考にさせていただきました。

www.pnkts.net

適当にリアクション通知という名前で作成。 Slackアプリ作成

Event Subscriptions>Enable Eventsを有効にして先ほどメモしておいたGASのURLを貼り付けてVerified表示されることを確認します。

Event Subscriptions

Subscribe to events on behalf of usersreaction_addedを追加します。

Subscribe to events on behalf of users

OAuth & Permissions>Scopesで以下を設定してアプリをインストール。(App Installから)表示されるOAuth Access TokenをGASのプロパティ(OAUTH_ACCESS_TOKEN)に定義します。

User Token Scopes

参考

www.lancard.com

Incoming Webhooks設定

GASからメッセージ投稿するためにIncoming Webhooks>Activate Incoming Webhooks を有効にします。

Webhook URLs for Your Workspaceワークスペースのチャンネル(作成した#reaction)に追加します。

*以前はicon_emojiも投稿できたみたいですが、できなくなったようなのでtextに絵文字リアクションを追加して投稿する実装にしています。

Reference: Message payloads | Slack

Slack での Incoming Webhook の利用 | Slack

つまづいた点

スレッド対応

元メッセージURLの生成とユーザID取得用にslack APIconversations.historyを使っていましたが、スレッドの場合thread_tsも必要だったのでそれがが取れるconversations.repliesを使うように変更しました。 スレッド時のURL構成やAPIのresponseなどドキュメントを調べたりけっこう時間かかりました。

conversations.replies method | Slack

非同期処理の制御(Promise→Promise.all)

そのままだとAPIでのデータ取得前にWebhook処理が走ってしまうので、Promiseを使って順次処理していましたが、APIでのデータ取得は順番を気にしなくていいのでPromise.allを使うようにリファクタリングしました。

Promise.allでコードがかなりスッキリしたと思います。

参考

qiita.com

google github アシスタントの連携

Chrome拡張機能をインストールしてもGASの画面に全然反映されず困りましたが、こちらにある「v4.0.7を手動でインストール」で解決しました。

Google Apps Script GitHub アシスタントが表示されない&Google認証でエラー This app is blocked - Qiita

Google Apps Script GitHub アシスタント - Chrome ウェブストア

運用

最初に書いたとおり夫婦間用Slackでメンバーは2人なのでメッセージにメンションはつけず通知設定をすべての新しいメッセージにしていて、#reactionチャンネルだけメンションのみ設定で自分の投稿に対するリアクションだけ通知がくるようにしています。

最後に

実装から記事をまとめるまでちょっと時間が空いているので設定の流れなど違ってる部分があるかもしれませんm(__)m

#reactionチャンネルに常にすべてのリアクション情報が投稿される点はかなり微妙ですが、Slack APIもGASも初めて触ったのでいろいろ勉強になりました。

何より、今までは「了解」などの返事 をいちいちメッセージでスタンプ投稿していたのが、リアクションでいけるようになったのは個人的にかなり良かったです。

追記(2021/2/22)

昨日から夫のAndroidにSlackのリアクション通知がくるようになったらしく...。iPhoneには来ていないのでAndroid版のみ実装されたのか、ベータ版で一部ユーザに公開されているのか、どちらにしてもリアクション通知が公式で導入されたらアプリ不要ですw