ShrineでRubyにファイルをアップロードする最良の方法。 パート2.ブートローダー

これは神社に関する一連の投稿の第2部です。 このシリーズの記事の目的は、既存のファイルダウンローダーに対するShrineの利点を示すことです。






以前の投稿で、私が神社を創る動機になったことについて話しました。 この記事では、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は現在、 ファイルシステムS3FogFlickrCloudaryTransloaditUploadcareImgixGridFSおよび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
      
      





依存関係






ファイルをダウンロードするためのほとんどのライブラリには、かなり巨大な依存関係があります。



搬送波





クリップ





整頓





一方、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/



著者のブログのオリジナルシリーズの記事:






All Articles