以前の投稿で、私が神社を創る動機になったことについて話しました。 この記事では、Shrineの基盤であるストレージ、ブートローダー、アップロードされたファイルを紹介します。
保管
Shrineの「リポジトリ」は、特定のストレージサービス(ファイルシステム、S3など)でファイル管理をカプセル化するプレーンなRubyオブジェクトです。 リポジトリには、次の5つのメソッドが含まれている必要があります。
class MyStorage def upload(io, id, **options) # `io` `id` end def url(id) # URL- `id` end def open(id) # `id` IO end def exists?(id) # , end def delete(id) # end end
Shrineストレージは直接構成され、オプションをコンストラクター(Refileから借用)に
Shrine.storages
、
Shrine.storages
に登録する必要があります:
Shrine.storages[:s3] = Shrine::Storage::S3.new( access_key_id: "abc", secret_access_key: "xyz", region: "eu-west-1", bucket: "my-bucket", )
Shrineは現在、 ファイルシステム 、 S3 、 Fog 、 Flickr 、 Cloudary 、 Transloadit 、 Uploadcare 、 Imgix 、 GridFSおよびSQLを サポートしていますので、選択してください。
独自のリポジトリを簡単に作成することもできます。これには、すべてが正しく機能するかどうかを自動的にチェックするマニュアルとリンターがあります。
ブートローダー
ローダーはShrineのサブクラスであり、特定の添付ファイル(CarrierWaveなど)をアンロードするロジックをカプセル化します。
class ImageUploader < Shrine # image uploading logic goes here end
アップローダーオブジェクトは、リポジトリのラッパーとして機能し、すべてのリポジトリに共通するロードのすべてのロジックを実行します。
- 処理中
- メタデータを抽出する
- ファイルの場所を生成する
- ダウンロード(この段階で、リポジトリへのアクセスが発生します)
- ダウンロードしたファイルを閉じる
ストレージオプションセットを使用してブートローダーのインスタンスを作成します。
Shrine.storages[:disk] = Shrine::Storage::FileSystem.new(...) uploader = ImageUploader.new(:disk) uploader.upload(image) #=> #<Shrine::UploadedFile>
ローダーはモデルについて知りません。 入力にアップロードされるファイルでのみ機能し、ダウンロードされたファイルの表現を出力に返します。 これは、ブートローダーがステートレスであることを示唆しているため、その動作が非常に予測可能になります。
アップロードされたファイル
ブートローダーを介してファイルがダウンロードされると、
#upload
メソッドは
Shrine::UploadedFile
オブジェクトを返します。 このオブジェクトは、リポジトリにアップロードされたファイルの完全な表現です。
uploaded_file = uploader.upload(image) #=> #<Shrine::UploadedFile> uploaded_file.id #=> "43ksd9gkafg0dsl.jpg" uploaded_file.storage #=> #<Shrine::Storage::FileSystem> uploaded_file.metadata #=> {...}
このオブジェクトはロードされた場所を知っているため、多くの便利なメソッドを提供できます。
uploaded_file.url # generates the URL uploaded_file.download # downloads the file to the disk uploaded_file.exists? # asks the storage if file exists uploaded_file.open { |io| ... } # opens the file for reading uploaded_file.delete # deletes the file from the storage
このオブジェクトはハッシュによってのみ定義されます。 リポジトリはインストールされたパラメーターで参照できるため、このハッシュはJSONでシリアル化され、データベース列に保存できるようになりました。
uploaded_file.data #=> # { # "id" => "df9fk48saflg.jpg", # "storage" => "disk", # "metadata" => {...} # } uploaded_file.to_json #=> '{"id":"df9fk48saflg.jpg","storage":"disk","metadata":{...}}'
Shrine::UploadedFile
オブジェクトはローダーに依存しません。 これは、
CarrierWave::Uploader::Base
および
Paperclip::Attachment
クラスとそのような依存関係を持つCarrierWaveとPaperclipとの大きな違いです。
IOの抽象化
Shrineは、
#size
、
#rewind
、
#eof?
#size
、
#rewind
#read
に応答するタイプ
IO
オブジェクトをロードできます
#eof?
そして
#close
(Refileなど)。 この厳密なインターフェイスを定義することにより、各Shrine関数はこれらのメソッドにのみ依存できることを認識します。つまり、
File
、
StringIO
、
ActionDispatch::Http::UploadedFile
、
Rack
タイプをロードするかどうかに関係なく正しく機能することを意味します。またはストリームによってダウンロードされる削除されたファイル。
さらに、
Shrine::UploadedFile
自体は
IO
タイプのオブジェクトであり、ダウンロードされたファイルを同じ統一されたインターフェースでラップします。 これにより、ある場所から別の場所にファイルを移動することが非常に便利になります。 さらに、ダウンロードとリロードのプロセスをスキップすることにより、いくつかのダウンロードを最適化することができます。たとえば、両方のファイルがS3からのものである場合はS3のコピーを使用します。
cache = ImageUploader.new(:s3_temporary) cached_file = cache.upload(image) store = ImageUploader.new(:s3_permanent) store.upload(cached_file) #=> performs an S3 COPY request
プラグインシステム
Shrineには、必要な機能を提供する小さなカーネル (500行未満のコード)が付属しています。 プラグインを介して追加機能をダウンロードできます 。 これにより、Shrineが何をどのように行うかを正確に選択し、使用する機能のコードのみをダウンロードする柔軟性が得られます。
# Loads the processing feature from "shrine/plugins/logging.rb" Shrine.plugin :logging, logger: Rails.logger
Shrineには35を超えるプラグインが付属しており、独自のプラグインを簡単に作成できます。 Shrineプラグインシステムは、以前に書いた Rodaを改造したものです。
さらに、Shrineローダーを継承できます( CarrierWaveとは異なります )。
Shrine.plugin :logging # enables logging for all uploaders class ImageUploader < Shrine plugin :backup # stores backups only for this uploader (and its descendants) end
依存関係
ファイルをダウンロードするためのほとんどのライブラリには、かなり巨大な依存関係があります。
搬送波
- ActiveSupport-これらのすべてのデコイパッチがほしくない
- ActiveModel- ライブラリなしで検証を実行してみませんか?
- MIME ::タイプ-ファイルの内容からMIMEタイプを決定することをお勧めします
クリップ
- ActiveSupport-繰り返しますが、おとりパッチを一切持たないようにしたいです
- ActiveModel-わかりました、とにかく、ActiveRecordにはActiveModelとActiveSupportの両方が必要です
- コカイン-Open3 Monstrous Command Shell Library
- MIME ::タイプ-MIMEタイプのスプーフィングの検出に問題があります
- MimeMagic-十分なファイルユーティリティ
整頓
- RestClient-簡単なファイルアップロードのための巨大なソリューション
- Sinatra-これは問題ありませんが、 Rodaはより軽い代替手段です。
- MIME ::タイプ-ファイルの内容からMIMEタイプを決定することをお勧めします
一方、Shrineには必須であるが簡単な依存関係が1つだけあります-Downです。 Downは、 open-uriを改善し、ストリーミングをサポートするnet / httpファイルダウンロードラッパーであり、ほとんどすべてのShrineリポジトリで使用されます。
さらに、使用する機能のコードのみをダウンロードするため、Shrineは通常非常に高速でロードされます。 他のローダーの場合、不要な可能性があるすべての機能のコードをダウンロードする必要があります。 たとえば、ShrineはロードされたプラグインなしでCarrierWaveより35倍速くロードされ、すべてのロードされた( source )プラグインで7倍速くロードされます。
まとめ
各高レベルインターフェイスには、適切な基盤が必要です。 したがって、どのレベルの抽象化を使用しても、何が起こっているのかを常に理解できます。 Shrineの基本は、
Storage
、
Shrine
Shrine::UploadedFile
クラスで構成され、各クラスには明確に定義されたインターフェースと責任があります。
オリジナル: https : //twin.github.io/better-file-uploads-with-shrine-uploader/
著者のブログのオリジナルシリーズの記事: