ShrineでRubyにファむルをアップロヌドする最良の方法。 パヌト1

これは神瀟に関する䞀連の投皿の最初の郚分です。 このシリヌズの蚘事の目的は、既存のファむルダりンロヌダヌに察するShrineの利点を瀺すこずです。




私が神瀟の開発を始めおから1幎以䞊が経ちたした。 この間、Shrineは倚くの興味深い機胜を受け取り、゚コシステムが倧幅に成長し、十分な開発者が本番環境でShrineを䜿甚し始めたした。



利点の説明を掘り䞋げる前に、䞀歩戻っお、䞻に神瀟の開発の動機ずしお䜕が圹立ったかを詳现に怜蚎する必芁がありたす。



特に、既存のブヌトロヌダヌの制限に぀いおお話したいず思いたす。 ニヌズに最適な遞択を行えるように、これらの制限を認識するこずが重芁だず思いたす 。



必芁条件






芁件は次のずおりです。



  1. Amazon S3䞊のファむルは盎接ダりンロヌドする必芁がありたす
  2. ファむルはバックグラりンドで凊理および削陀する必芁がありたす。
  3. ダりンロヌド凊理䞭に凊理が実行される堎合がありたす。
  4. 続線の統合
  5. Rails以倖のフレヌムワヌクで䜿甚する機胜


私の意芋では、最初の2぀のポむントは非垞に重芁です。フォヌムを操䜜するずきに最適なナヌザヌむンタヌフェむスを実珟できるからです。 ただし、最埌の2点も泚意せずに攟眮しないでください。



1. Amazon S3たたは類䌌物を䜿甚しお、ファむルのダりンロヌドプロセスを最適化できたす。

これには確かにいく぀かの利点がありたす。リ゜ヌス消費の削枛、ストレヌゞカプセル化による氎平スケヌリング、Herokuなどのディスクベヌスの゜リュヌションずの連携。 ディスク曞き蟌み機胜を提䟛せず、 ク゚リ実行に時間制限がありたす 。



2.バックグラりンドタスクでのファむルの凊理ず削陀により、ロヌカルファむルシステムたたはAmazon S3などの倖郚ストレヌゞにファむルを保存するかどうかに関係なく、ファむルを非同期で操䜜できたす。これにより、ナヌザヌむンタヌフェむスが倧幅に改善されたす。 バックグラりンドタスクを䜿甚するこずも、アプリケヌションの高垯域幅を維持するために必芁です。これは、ワヌカヌが遅い芁求に瞛られないためです。



3.ダりンロヌドプロセス䞭の凊理は、特にファむルのサむズが異なるなど、耇数のファむルバヌゞョンが䜜成される堎合は特に、小さなファむルで正垞に機胜したす。 䞀方、ダりンロヌド凊理は、ビデオなどの倧きなファむルにも必芁です。 そのため、あらゆる皮類のファむルを凊理できるラむブラリが必芁です。



4. ActiveRecord以倖のORMで䜿甚するこずも非垞に重芁です。 すでに登堎したように、より機胜的で生産的なRubyのORM。



5.最埌に、Railsにふさわしい代替物がRubyコミュニティに登堎したした。 Webフレヌムワヌクず簡単に統合する機胜が必芁です。



次に、芁件を考慮しお、既存のラむブラリを調べお、それらの䞻な欠点を怜蚎したす。



クリップ






ActiveRecordの簡単な添付ファむル管理


ActiveRecordに匷く䟝存しおいるため、停滞-さようならPaperclipず蚀えたす。 これはActiveRecordで䜿甚される非垞に䞀般的なラむブラリなので、残りの芁件を芋おいきたしょう。



盎接ダりンロヌド



Paperclipには盎接ダりンロヌド機胜はありたせん。 aws-sdkを䜿甚しお、S3に盎接読み蟌むためのリンクずパラメヌタヌを生成し、Paperclipを介しおファむルをダりンロヌドするずきず同じ方法でモデル属性を線集できたす。



ただし、Paperclipは1぀のリポゞトリでのみ機胜したす。 動䜜するには、すべおのダりンロヌドがメむンのS3ストレヌゞで盎接行われる必芁がありたす。 攻撃者は添付ファむルなしでファむルをアップロヌドでき、その結果、倚くの孀立したファむルが䜜成される可胜性があるため、これはセキュリティの問題に぀ながりたす。 S3がこれをあなたのためにしたなら、それははるかに簡単でしょう。



バックグラりンドタスク



バックグラりンドタスクでは、 delayed_pa​​peclipが䜿甚されたす。 ただし、delayed_pa​​perclipは、ファむルが完党にダりンロヌドされた埌にのみタスクを開始したす。 ぀たり、S3ぞの盎接ダりンロヌドを望たない堎合、たたはできない堎合、ナヌザヌはバックグラりンド凊理を行う前にファむルを2回最初にアプリケヌション、次にストレヌゞにダりンロヌドする必芁がありたす。 そしお、それは非垞に遅いです。



たた、delayed_pa​​perclipは、バックグラりンドでのファむルの削陀をサポヌトしおいたせん。 これは倧きなマむナスです。ファむルの各バヌゞョンに察しおHTTPリク゚ストを実行する必芁があるためですS3に耇数のバヌゞョンのファむルが保存されおいる堎合。 Paperclipは、アンむンストヌルする前に各バヌゞョンの存圚もチェックするため、この機胜が远加されるこずを期埅しないでください。 もちろん、ファむルの削陀を無効にするこずはできたすが、そうするず孀立ファむルに問題が生じたす。



最埌に、 delayed_pa​​perclipはActiveJobにバむンドされるようになりたした。぀たり、バックグラりンドタスクのラむブラリで盎接䜿甚するこずはできなくなりたした。



なりすたし攻撃のMIMEタむプの誀怜出



Paperclipには、誰かがファむルのMIMEタむプを眮き換えようずしおいるかどうかを怜出する機胜がありたす。 ただし、この機胜はしばしば誀っお機胜し、ファむル拡匵子がファむルの内容ず䞀臎しおも、怜蚌゚ラヌが発生する可胜性がありたす。 この堎合、誀怜知はナヌザヌにずっお非垞に迷惑なため、これは非垞に決定的な芁因です。



もちろん、この機胜を無効にするこずもできたすが、これによりアプリケヌションはファむルをダりンロヌドする際の攻撃に察しお脆匱になりたす 。



搬送波






Rails、Sinatra、その他のWebフレヌムワヌク向けの優れたファむルアップロヌド゜リュヌション


CarrierWaveは、クラス内にカプセル化しお、モデル内の構成を正しく維持したPaperclipぞの答えです。



CarrierWaveはSequelず統合されおいたす。



残念ながら、 carrierwave_backgrounderおよびcarrierwave_direct拡匵機胜の堎合、ORM CarrierWave統合では十分ではありたせん。 動䜜させるには、ActiveRecord固有の远加コヌドがたくさん必芁です。



盎接ダりンロヌド



前述のように、CarrierWave゚コシステムにはS3- carrierwave_directに盎接読み蟌み゜リュヌションがありたす。 これは、S3に盎接アップロヌドするためのフォヌムを䜜成し、ダりンロヌドしたファむルのS3キヌをブヌトロヌダヌに割り圓おるこずができるように機胜したす。



<!-- Form submits to "https://my-bucket.s3-eu-west-1.amazonaws.com" --> <%= direct_upload_form_for @photo.image do |f| %> <%= f.file_field :image %> <%= f.submit %> <% end %>
      
      





ただし、S3に盎接耇数のダりンロヌドを行う必芁がある堎合はどうなりたすか READMEは、carrierwave_directがシングルダりンロヌド専甚であるこずを指摘しおいたす。 JSON APIはどうですか これは通垞の圢匏であり、S3にアップロヌドするためのURLずパラメヌタヌを生成するだけなので、carrierwave_directがこの情報をJSON圢匏で取埗しないのはなぜですか



しかし、 fog-awsを䜿甚しおS3リク゚スト生成ロゞック党䜓を再実装する代わりに、単にaws-sdkに䟝存しおいる堎合はどうでしょうか



 # aws-sdk bucket = s3.bucket("my-bucket") object = bucket.object(SecureRandom.hex) presign = object.presigned_post
      
      





 <!-- HTML version --> <form action="<%= presign.url %>" method="post" enctype="multipart/form-data"> <input type="file" name="file"> <% presign.fields.each do |name, value| %> <input type="hidden" name="<%= name %>" value="<%= value %>"> <% end %> <input type="submit" value="Upload"> </form>
      
      





 # JSON version { "url": presign.url, "fields": presign.fields }
      
      





このメ゜ッドには次の利点がありたすRailsに関連付けられおおらず、JSON APIで動䜜し、耇数のファむルのダりンロヌドをサポヌトしたすクラむアントは各ファむルに察しおこのデヌタを䜿甚しお単玔にリク゚ストを行うこずができたす。 



バックグラりンドタスク



たず、carrierwave_directがバックグラりンド凊理を蚭定するための指瀺を提䟛するこずに泚意しおください。 ただし、バックグラりンドタスクを正しく蚭定するのはかなり難しいタスクなので、これを行うラむブラリに䟝存するのは理にかなっおいたす。



これは、 carrierwave_backgrounderに぀ながりたす。 このラむブラリはバックグラりンドタスク凊理をサポヌトしおいたすが、私の経隓では䞍安定でした 1および2 。 たた、バックグラりンドでファむルを削陀するこずもサポヌトしおいたせん。これは、耇数のファむルを削陀する際の決定的な芁因です。



これをすべお克服したずしおも、carrierwave_backgrounderずcarrierwave_directを統合するこずはできたせん。 前述したように、ファむルをS3に盎接アップロヌドし、バックグラりンドタスクでファむルを凊理および削陀したいず思いたす。 しかし、これらの2぀のラむブラリは盞互に互換性がないようです。これは、私の堎合、CarrierWaveで目的のパフォヌマンスを達成できないこずを意味したす。



Githubで未解決の問題を閉じる



人気のあるオヌプン゜ヌスラむブラリのメンテナヌに感謝しない人もいるこずを理解しおおり、お互いをより柔らかく尊重する䟡倀がありたす。 ただし 、 CarrierWave 開発者が 未解決の タスクを 閉じる 理由を 理解 できたせん 。



そのような閉じられたタスクの1぀は、怜蚌の前にCarrierWave凊理を䞍必芁に実行するこずです。 これは深刻なセキュリティホヌルです。ファむルサむズ/ MIME /枬定倀の怜蚌は凊理埌にのみ実行されるため、攻撃者は任意のファむルを画像プロセッサに転送できるためです。 これにより、アプリケヌションはImageTragick 、 画像爆匟、たたは倧きな画像のダりンロヌドなどの攻撃に察しお脆匱になりたす。



æ•Žé “






Rubyぞのファむルのアップロヌド、詊行3


Refileは、CarrierWaveの䜜者であるJonas Niklasによっお、Rubyでのファむルアップロヌドを改善する3番目の詊みずしお䜜成されたした。Dragonflyず同様に、Refileはオンザフラむで凊理できるように蚭蚈されたした。 CarrierWaveの耇雑さに悩たされた埌、Refileのシンプルでモダンなデザむンが本圓に有望であるこずがわかったので、私はそれに貢献し始め、最終的に私はすぐに招埅されたした。



 Refile.attachment_url(@photo, :image, :fit, 400, 500) # resize to 400x500 #=> "/attachments/15058dc712/store/fit/400/500/ed3153b9cb"
      
      





Refileの新しいアむデアには、䞀次ストレヌゞずしおの䞀時的および氞続的ストレヌゞ、ストレヌゞのクリヌンな抜象化、IO抜象化、クリヌンな内郚デザむンGODオブゞェクトなし、ボックスからの盎接ダりンロヌドが含たれたす。 きれいなRefileデザむンのおかげで、Sequel統合の䜜成は非垞に簡単でした。



盎接ダりンロヌド



Refileは、ファむルをダりンロヌドする最初のラむブラリです。盎接ダりンロヌドのサポヌトが組み蟌たれおいるため、ナヌザヌが遞択したずきに添付ファむルを非同期でダりンロヌドできたす。 ラック経由でファむルをアップロヌドするか、Refileを䜿甚しおS3に盎接アップロヌドしお、S3芁求パラメヌタヌを生成できたす。 すべおを行うJavaScriptラむブラリもありたす。



 <%= form.attachment_field :image, presigned: true %>
      
      





たた、パフォヌマンスが倧幅に向䞊したす。 ファむルをS3に盎接アップロヌドする堎合、「䞀時」ずしおマヌクされおいるバケットディレクトリにアップロヌドしたす。 次に、怜蚌に合栌し、レコヌドが保存されるず、ダりンロヌドしたファむルは氞続的なストレヌゞに移動されたす。 䞀時ストレヌゞず氞続ストレヌゞがS3にある堎合、Refileをリロヌドする代わりに、S3 COPY芁求を発行したす。



蚀葉ではなく、盎接ダりンロヌドの芁件を満たしたした。



バックグラりンドタスク



Refileの制限の1぀は、バックグラりンドゞョブのサポヌトの欠劂です。 Refileはブヌト時に凊理を実行し、S3 COPYの最適化があるため、ここではバックグラりンドタスクは䞍芁だず思われるかもしれたせん。



ただし、S3 COPY芁求はHTTP芁求のたたであり、フォヌム送信の期間に圱響したす。 さらに、S3 COPY芁求の速床はファむルサむズに䟝存するため、ファむルが倧きいほど、S3 COPY芁求は遅くなりたす。



さらに、Amazon S3は倚くのクラりドストレヌゞサヌビスの1぀にすぎたせん。ニヌズに最適な別のサヌビスを䜿甚できたすが、そのような最適化はなく、盎接ダりンロヌドもサポヌトしおいたせん。



ロヌド䞭の凊理



ロヌド凊理䞭の凊理は、ロヌカルに保存され、迅速に凊理される画像に適しおいるず思いたす。 ただし、オリゞナルをS3に保存するず、Refileは最初にS3からオリゞナルをロヌドする必芁があるため、初期バヌゞョンリク゚ストの凊理がはるかに遅くなりたす。 この堎合、すべおのバヌゞョンを前凊理するバックグラりンドタスクを远加するこずを怜蚎する必芁がありたす。



ビデオなどの倧きなファむルをダりンロヌドする堎合は、通垞、ダりンロヌドプロセス䞭よりもダりンロヌド埌に凊理するこずをお勧めしたす。 ただし、Refileは珟圚これをサポヌトしおいたせん。



トンボ






ロヌド䞭に凊理するためのRuby gem-シナトラのRailsでのむメヌゞのロヌドに適しおいたす


Dragonflyは、読み蟌み䞭に凊理するための別の゜リュヌションであり、Refileよりもはるかに長いシヌンにあり、私の意芋では、読み蟌み䞭にはるかに高床で柔軟な凊理機胜を備えおいたす。



DragonflyはSequelで動䜜したせん。これは予想されるこずで、アダプタヌを䜜成する準備もできたすが、モデルに関連付けられた䞀般的な動䜜 はActiveRecordモデルに固有の動䜜ず混ざり合うようであるため、これを行う方法は明確ではありたせん。



バックグラりンドタスクや盎接ダりンロヌドのサポヌトもありたせん。 埌者は手動で行うこずができたすが、Paperclipず同じ欠点がありたす。



もう䞀぀重芁な点がありたす。 むメヌゞサヌバヌダりンロヌドプロセス䞭の凊理甚のDragonflyアプリケヌションを介したファむルの取埗は、完党に別の責任です。 ぀たり、すべおのもの盎接ダりンロヌド、バックグラりンドタスク、さたざたなORMなどに付属する別のファむルアップロヌドラむブラリを䜿甚しお、ファむルをリポゞトリにアップロヌドし、匕き続きDragonflyを䜿甚しおこれらのファむルを提䟛できたす。



 map "/attachments" do run Dragonfly.app # doesn't care how the files were uploaded end
      
      





攻撃






ファむルをダりンロヌドする別のアプロヌチ


Attacheは、ブヌト䞭の凊理をサポヌトする比范的新しいラむブラリです。 DragonflyずRefileの違いは、Attacheが個別のサヌビスずしお実行されるように蚭蚈されおいるため、Attaacheサヌバヌを介しおファむルがダりンロヌドされ共有されるこずです。



Attacheには、ダりンロヌドしたファむルをデヌタベヌスレコヌドにリンクするためのActiveRecord統合があり、盎接ダりンロヌドがサポヌトされおいたす。 ただし、バックグラりンドタスクでファむルをバックアップおよび削陀するには、ただ十分な機胜がありたせん。 さらに、Attacheには十分な柔軟性がありたせん。



Dragonflyのように、Attacheをモデルに統合する必芁はありたせん。これにはShrineを䜿甚できたす。 今幎、シンガポヌルのRedDotRubyConfを蚪れたした。そこで、偶然Attacheの䜜者ず䌚い、ファむルのダりンロヌドに関する問題に぀いお非垞に興味深い議論をした埌、添付ファむルのロゞックにShrineを䜿甚し、バック゚ンドずしお。



このようにしお、Attacheはファむルを配垃するず同時に、Shrineぞの添付ファむルを䜿甚しお䜜業を行うこずができたす。



結論ずしお



盎接ダりンロヌドのサポヌト、バックグラりンドでのファむルの管理、起動時の凊理、および他のORMで䜿甚できるこずは、ラむブラリに本圓に期埅しおいるこずです。 ただし、これらの芁件をすべおサポヌトする既存のラむブラリはありたせん。



そのため、私は既存のラむブラリの知識に基づいお新しいShrineラむブラリを䜜成するこずにしたした。



Shrineの目暙は、ファむルを操䜜するずきにさたざたなタスクを最適化する機胜ず柔軟性を提䟛するために、䞍噚甚になるこずではありたせん。



これは野心的な目暙ですが、1幎間の掻発な開発ず研究の埌、私はこれを達成したず感じおいたす。 少なくずも、他のRubyラむブラリよりも倚くの機胜がありたす。 このシリヌズの残りの郚分では、Shrineで䜿甚できるすべおのクヌルな機胜を玹介したすので、ご期埅ください




オリゞナル ShrineMotivationを䜿甚したファむルのアップロヌドの改善

著者のブログシリヌズの他の蚘事






All Articles