タケユー・ウェブ日報

Ruby on Rails や Flutter といったWeb・モバイルアプリ技術を武器にお客様のビジネス立ち上げを支援する、タケユー・ウェブ株式会社の技術ブログです。

Flow.js + S3 + Ruby で分割アップロード バックエンド実装メモ

flowjs.png 大容量ファイルのアップロードのため、[Flow.js](https://github.com/flowjs/flow.js/tree/master)を使って分割を実装しました。その時のメモ。 ## 前提 インスタンスを作ったり消したりするし、複数インスタンスの場合もあるので、ローカルファイルシステム内に`chunk`を置きたくない。 ## 参考 ### [Ruby backend in Sinatra](https://github.com/flowjs/flow.js/blob/master/samples/Ruby%20backend%20in%20Sinatra.md) タイトルまま。 これをベースにFileの代わりに`AWS::S3`を使うようにしました。 ### [Efficient Amazon S3 Object Concatenation Using the AWS SDK for Ruby](http://ruby.awsblog.com/post/Tx2JE2CXGQGQ6A4/Efficient-Amazon-S3-Object-Concatenation-Using-the-AWS-SDK-for-Ruby) S3に置いた複数のファイルをS3上で結合する方法についての解説記事。 ## コードサンプル(Rails) 簡略化するとこんな感じでとりあえずダサいですが動きます。 実際は結合処理はここでは行わず、キューやSWFを使った方がよいと思います。たぶん。 ```ruby class UploadController < ApplicationController def get obj = bucket.objects[chunk_file_path] head obj.exists? ? 200 : 404 end def post save_file! combine_file! if last_chunk? head 200 end private def save_file! obj = bucket.objects[chunk_file_path] obj.write Pathname(File.open(params['file'].tempfile.to_path)) end def last_chunk? params[:flowChunkNumber].to_i == params[:flowTotalChunks].to_i end def chunk_file_path File.join chunk_file_directory, "#{params[:flowFilename]}.part#{params[:flowChunkNumber]}" end def chunk_file_directory File.join 'tmp', 'flow', 'chunks', params[:flowIdentifier] end def combine_file! obj = bucket.objects[final_file_path] upload = obj.multipart_upload file_chunks.each do |file_chunk_path| upload.copy_part File.join(bucket.name, file_chunk_path) end upload.complete() bucket.objects.with_prefix(chunk_file_directory).delete_all end def final_file_path File.join final_file_directory, params[:flowFilename] end def final_file_directory 'src' end def file_chunks bucket.objects.with_prefix(chunk_file_directory). collect(&:key). sort_by do |f| f.split('.part')[1].to_i end end def bucket return @bucket if defined?(@bucket) s3 = AWS::S3.new @bucket = s3.buckets['sample'] end end ```