以前の投稿で、私が神社を創る動機になったことについて話しました。 この記事では、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/
著者のブログのオリジナルシリーズの記事: