brewでmacのpostgresを14にアップグレードした際にpgを使ってるrailsが立ち上がらなくなった。(M1 Macです)

/Users/komagata/go/src/github.com/fjordllc/bootcamp/vendor/bundle/ruby/3.1.0/gems/bootsnap-1.13.0/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:32:in `require': dlopen(/Users/komagata/go/src/github.com/fjordllc/bootcamp/vendor/bundle/ruby/3.1.0/gems/pg-1.4.4/lib/pg_ext.bundle, 0x0009): Library not loaded: /opt/homebrew/opt/postgresql/lib/libpq.5.dylib (LoadError)
  Referenced from: /Users/komagata/go/src/github.com/fjordllc/bootcamp/vendor/bundle/ruby/3.1.0/gems/pg-1.4.4/lib/pg_ext.bundle
  Reason: tried: '/opt/homebrew/opt/postgresql/lib/libpq.5.dylib' (no such file), '/usr/local/lib/libpq.5.dylib' (no such file), '/usr/lib/libpq.5.dylib' (no such file), '/opt/homebrew/Cellar/postgresql@14/14.5_5/lib/libpq.5.dylib' (no such file), '/usr/local/lib/libpq.5.dylib' (no such file), '/usr/lib/libpq.5.dylib' (no such file) - /Users/komagata/go/src/github.com/fjordllc/bootcamp/vendor/bundle/ruby/3.1.0/gems/pg-1.4.4/lib/pg_ext.bundle
/
  opt/
    homebrew/
      opt/
        postgresql/
          lib/
            postgresql@14/
              libpq.5.dylib <- 有る
            libpq.5.dylib <- 無い

/opt/homebrew/opt/postgresql/libの中にはlibpq.5.dylibが無くてpostgresql@14ってディレクトリの中にある。なんかシンボリックリンク作成やコピーのミスのような雰囲気がするけど、とにかくライブラリの位置が変わってるっぽい。

とりあえずシンボリックリンクを貼ったら動いた。HomebrewのFormulaのreposを覗いてみたけどちょっとよくわからなかった。

$ ln -s /opt/homebrew/opt/postgresql/lib/postgresql@14/libpq.5.dylib /opt/homebrew/opt/postgresql/lib/libpq.5.dylib

abstract_notifierで通知を実装する - komagataのブログ

ここでminitestでのテストが書きづらいのでPRするって書いてましたが、それがマージされたバージョン0.3.2がリリースされました。

READMEに書いてありますがminitestではこういうふうに書くといい感じです。

require 'abstract_notifier/testing/minitest'

class EventsNotifierTestCase < Minitest::Test
  include AbstractNotifier::TestHelper

  test 'canceled' do
    assert_notifications_sent 1, identify: "123", body: "Alarma!" do
      EventsNotifier.with(profile: profile).canceled(event).notify_now
    end

    assert_notifications_enqueued 1, identify: "123", body: "Alarma!" do
      EventsNotifier.with(profile: profile).canceled(event).notify_later
    end
  end
end

最近のrailsでのパスワード認証gemって何使ってます?

The Ruby Tool BoxのWeb Authentiationカテゴリーを参照。

devise

やってくれることは多いがカスタマイズしづらいので嫌う人も多い。俺はこれ使ってる。 しかし登場から時間が経ち、railsの仕様に追従していくにつれて初期の設計に無理がきてる感。特にrails7からはさらに。

sorcery

やってくれることは少ないが、カスタマイズしやすい。bootcampのアプリはこれを使ってる。(確か @hrysd が入れた) リニューアル版sorcery(sorcery-rework)が別リポジトリで進んでるが、当分完成しそうにな。

authlogic

使ったことないけどちょっと古い感?

clearance

使ったことないけどちょっと古い感2

railsの基本機能を使って自作

これが多いのかも?

個人的には認証などのセキュリティが大きく絡むところはなるべくgemなどみんなが見ている(セキュリティパッチがすぐ入りやすい)ところのを使いたいな〜と思っております。

みなさんのプロジェクトではどんな感じでしょう? 温度感が知りたい感。

railsの6系最新(6.1.4.4)とrubyの最新(3.1.0)にアップグレードするときに対応してないgemにPRを送る作業をやっています。

bootcampのrails 6.1.4.4

https://github.com/fjordllc/bootcamp/pull/4101

pgのwarningが残ってる。(こういうところも粘り強く対応できるようになっていきたい)

bootcampのruby 3.1.0

https://github.com/fjordllc/bootcamp/pull/4108

@ima1zumiさんが3.0.2にアップデートする作業を初めてくれて、そこに乗る形でやりとりさせていただいてました。3.0.3だと起きるけど3.1.0では起きない問題があったので一気に上げちゃう方針に。こういうところも粘り強く(略

おかげでCI通ったようなのであと一歩。

sorcery-jwt

https://github.com/hayfever/sorcery-jwt/pull/14

sorcery-jwtはdependencyの設定を変えないと最新のsorceryで使うことができない。sorcery-jwt自体、リニューアル後(予定)の新sorceryではcore pluginになる予定だそうで、こちらのgemをもうupdateする気はないのかもしれない。とりあえずforkして対応してるけど、メールを送ってみる予定。

ActiveFlag

https://github.com/kenn/active_flag/pull/19

これはbundlerのバージョンによるものだった。

今後

ruby 3.1.0にできたら次はrails 7.0.1に上げる作業をやる予定。こっちも色々PRに必要になるでしょう。

ActiveFlagのテストでrequire 'set'が必要かもという問題。

人によって結果が違うのなぜかな〜という状態だったんですが、(実行していただいた方々ありがとうございます)

bundler 2.2.8でrequire 'set'がなくなったのが原因だそうです。

https://github.com/kenn/active_flag/pull/19#issuecomment-1025093171

Image from Gyazo

この行。

https://github.com/rubygems/rubygems/pull/4297/files#diff-04ae823e98259f697c78d2d0b4eab0ced6a83a84a986578703eb2837d6db1a32L4

ほぼ標準といえるようなgemから依存がなくなるとこういうことが起きるんですね。setについて他のライブラリでも似たようなこと起きてるかもしれません。環境を示すときはbundlerのバージョンも示した方がいいんだなと勉強になりました。

フィヨルドブートキャンプではチャットをSlackからDiscordに移行しようとしています。

DiscordにはSlackのようなReminder機能がメジャーなBotの中には無いので定期的なミーティングのリマインドを簡単に移行することができません。

有名なreminder-botでは「72時間おきにリマインド」のような単純Interval形式しか対応してません。「毎月1日の9時にリマインド」のようなことができないので困ってました。

ブートキャンプでは現在リマインドすべきものは3つしかなく、SlackのようなReminder Botを僕が作るのも面倒なのでCloud Functionsでやってみました。

流れ

Cloud Scheduler -> Pub/Sub -> Cloud Functions -> Discord

Cloud Schedulerでcronと同じインターフェースで時間を指定できるのでjobを作ります。

Image from Gyazo

ターゲットにはHTTPを指定してリクエストを飛ばしたりもできますが、Pub/Subも指定できます。

Pub/Subはややこしいかと思ってたんですが単に名前決めて作るだけでした。

Cloud FunctionsではPub/Subで作ったイベントをSubscriptionしてそのタイミングで実行できます。

コード

Image from Gyazo

require 'functions_framework'
require 'net/http'
require 'json'

FunctionsFramework.cloud_event 'reminder_sub' do |event|
  uri = URI.parse(ENV['WEBHOOK_URL'])
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  params = { "content" => "💬 14:00からふりかえりミーティングが 🔈ミーティング チャンネルで始まります。" }
  headers = { "Content-Type" => "application/json" }
  http.post(uri.path, params.to_json, headers)
end

Discordの発言はwebhookにPOSTするだけです。Cloud Schedulerからpayloadに何か値を入れてれば上記のeventの中にそれが(base64でエンコードされて)入っているのでその内容を使って処理を分けたりもできます。(実際のコードでは3種類の通知をそれで出し分けてます。)

最初のテンプレにGemfileも含まれていて、gemを使うのも何にも苦労せずでした。

Image from Gyazo

Cloud Functionsは高度な用途もありますが、こういうふうに週1回しか動かないクソちょっとしたプログラムを動かすにも安くていいなと思います。

(ハライチ感)

Foo.configure do |config|
  config.name = "foo"
  config.email = "foo@example.com"
end

こっちでもかけたりする。

Foo.config.name = "foo"
Foo.config.email = "foo@example.com"

こういうやつ。

実装は大体こういう感じになってる。

module Foo
  class << self
    def configure
      yield config
    end

    def config
      @_config ||= Config.new
    end
  end

  class Config
    attr_accessor :name, :email

    def initialize
      @name = "no name"
      @email = "default@example.com"
    end
  end
end

これrubyでよくあるけど(他の言語であんま見ない)これなんて呼ぶのがいいのかな?

フィヨルドブートキャンプで説明する時にこれを表現したくても

「blockで設定するやつ」

としか言えない。

「なんでこれで設定できるんですか?」

と言われても、口で説明するのが大変なのでここに置いておきます。

fjordcop作った - komagataのブログ

これをgemにしました。

rubocop-fjord

gemにした理由は、gistだと適当感があってこれにしたがってくださいと言い辛いからです。 メンテについては腹を括ったのでやっていきます。

とにかくエディタ論争とこういうルールについての議論をするのが辛い。

プログラミングスクールで使うことを念頭に置いているので他にも教育やスクールをやっている方には便利かも知れません。

group :development do
  gem 'rubocop-fjord', require: false
end

.rubocop.ymlにこう書く。

inherit_gem:
  rubocop-fjord:
    - "config/rubocop.yml"
    # - "config/rails.yml"

mentionable gemで簡単にmentionが実装できます。(こういうやつ → @komagata)

komagata/mentionable

インストール

gem 'mentionable'
$ bundle install

使い方

app/models/comment.rb:

class Comment
  mentionable_as :body

  def after_save_mention(new_mentions)
    p new_mentions # => ["@komagata", "@machida"]
  end
end

Commentモデルのbodyにmentionが含まれる文章が保存される場合、mentionable_asでそのカラムを指定したらデフォルトでafter_save_mentionメソッドが呼ばれるので実装して置けばOK。

そのカラムにメンションが含まれていた場合、そのメソッドがコールバックされます。

class Comment
  mentionable_as :body, on_mention: :on_mentioned, regexp: /:\w+:/

  def on_mentioned(new_mentions)
    p new_mentions # => [":komagata:", ":machida:"]
  end
end

コールバックメソッドの名前とメンションを抽出するための正規表現は独自のものが指定できる。

便利メソッド

comment = Comment.create(body: '@nobunaga @hideyosi Hi guys.')
comment.mentions # => ["@nobunaga", "@hideyosi"]
comment.new_mentions? # => true

comment.update(body: '@nobunaga @hideyosi @ieyasu Hi guys.')
comment.mentions # => ["@nobunaga", "@hideyosi", "@ieyasu"]
comment.mentions_were # => ["@nobunaga", "@hideyosi"]
comment.new_mentions # => ["@ieyasu"]
comment.new_mentions? # => true

#mentionsでメンションが取れる。

メンションを自分で実装するときの面倒な仕様として、

「メンションを含むテキストがupdateされた場合に増えた分のメンションだけ欲しい。(updateされるたびに通知が行くとうざい)」

というのがありますが、mentionable gemでは最初から新しく増えた分のメンションだけがコールバックメソッドに渡ってくるので楽です。

それらを自分で取る各種メソッドもあります。

  • #mentions: メンション全部
  • #mentions?: メンションある?
  • #new_mentions: 新しいメンション
  • #new_mentions: 新しいメンションある?
  • #mentions_were: 古いメンション

実際のサービスではコールバックメソッドの中でサイト内通知や通知メールを送ったりすればOK。

macデフォルトは古いのでbrewで入れる。

% brew install ctags

vim-tagsを入れる。

.vimrc:

Plug 'szw/vim-tags'

let g:vim_tags_project_tags_command = "/usr/local/bin/ctags -R {OPTIONS} {DIRECTORY} 2>/dev/null"
let g:vim_tags_gems_tags_command = "/usr/local/bin/ctags -R {OPTIONS} `bundle list --paths` 2>/dev/null"

:TagsGenerateする。(.gitがあると.git/tagsに作られるみたい便利)

  • C-]: 定義にとぶ
  • C-o: 前のバッファに戻る
  • C-i: C-oの逆

2020年07月06日修正:bundle showはDEPRECATEDなのでbundle listに修正。(これが原因でtagが読めなくなってた)