長いこと、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
- files
- directory
という階層を持つ形になっているんだけど、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? みたいなことが簡単に実現できるので、サクッと載せ替えてしまいました。とさ。