fogをやめてShrineにしてみた

長いこと、Ruby で単にストレージアクセスを抽象化するためなら fog が有力候補だと思っていたのですが、どうもそんなことねーな?と気づいた話。

fogとは

fog - The Ruby cloud services library

fog は storage に限らず cloud resource に対する API の wrapper として機能するもの。そこそこ歴史もある。

例えばこれを使うと理屈上 S3 へのアクセスも Google Cloud Storage へのアクセスも provider 設定の切り替えと認証情報のセット、プロジェクトのセット以外は全部同じように動く。はず。

Shrineとは

Shrine · File attachment toolkit for Ruby applications

Shrine は cloud 全般向けではなくて、Rails の model とかにファイルを添付する、その際に cloud storage も利用できるようにするためのもの。

やりたいこととfogの何で困ったのか

今回やりたかったことは Rails でもなければ Model とファイルの紐付けでもなんでもない、単にクラウドストレージのオブジェクトを読み書きしたい、それを local で手軽にテストしたい、という話だったのでファイル添付系の gem は最初から除外して考えていた。具体的には ActiveStorage とか CarrierWave とか Shrine とか Paperclip とかその辺。

で、じゃあ fog かと思って使い始めて fog-local でテストをがっつり動かしていざ fog-google に差し替えましたとなって急に雲行きがあやしくなった。

というのも、fog の API は

  • directories
    • directory
      • files
        • file

という階層を持つ形になっているんだけど、GCS 上で(権限不足が起きている際に)files がめちゃくちゃ遅くてtimeoutしてしまって何が起きているのか分からない

加えて、HTTP HEAD method を使ったオブジェクトの存在確認の API が GCS に存在しない。

ということでそもそも fog の API デザインが合わないという結論になった。

※ 実は GCS 側を S3 互換にして S3 の API を叩くという方法もあるんだけど、そうすると認証方法も変更になってしまうのでこれは避けた。具体的には GAE から GCS を叩く際に、イマドキは application default credentials というものがあるので、同一プロジェクト内の resource へアクセスするのであれば、アプリ側で認証情報に関して一切気にする必要がないんだけど、API を S3 互換にすると認証も S3 互換になるっぽいので、だいぶ面倒だなと思ってそこで考えるのをやめることにした。

[2020-10-29 追記] これについてはPermissionのエラーが確認できたのでfog固有の問題ではないようだ。ただしtimeoutでエラーの内容が確認できなくなってしまうという状態は非常に困るので、載せ替え自体は妥当な判断だったと言えるだろう。

Shrineは単なるオブジェクトアクセスでも便利

Shrine は Model へのファイル添付向けに Shrine::Attacher や Shrine::Attachment というものがあって、その例がトップページに掲載されているんだけど、実は単なるストレージアクセスを実現する Shrine::Storage という名前空間も存在している。この辺は fog などの他の gem に依存した実装になっているのかと思っていたがそうではなく、Shrine が独自に抽象化していて、この Shrine::Storage 以下の

  • upload
  • open
  • exists?

のメソッド群を使うと、File.write や File.exist? みたいなことが簡単に実現できるので、サクッと載せ替えてしまいました。とさ。

More