前提・実現したいこと
Rails5を使って、ユーザーが画像を選択し、自由にトリミングした上で投稿できる機能を実装中です。
Carrierwaveを用いた通常の実装はできたのですが、サーバーにherokuを使用しているのでアップロードが遅くなってしまうことを懸念し、jQuery file-uploadを使用して、クライアントサイドからS3に直接アップロードする方法を取ろうとしています。
画像をトリミングしない場合は問題なくこの方法で実装できたのですが、トリミングさせる際に、以下の問題が生じました。
JSの経験に乏しいので、ご助言いただきたいです…
参考記事:
Direct to S3 Image Uploads in Rails
Direct Upload of Image to S3 after Manual Cropping with Cropper.js
jQuery-File-Upload
発生している問題・エラーメッセージ
⑴元の画像の代わりに、トリミングした画像データをs3にアップロードできません。
以下のようにコードを書いたのですが、トリミングされる前の画像データがアップされてしまいます。
【追記】2回submitボタンを押すと、2回目の送信ではトリミング後の画像がアップされることがわかりました。(詳細は後述します。)
⑵また、このコードだと、画像を選択し直した場合、投稿が二つ作成されてしまいます。
Javascript
1$(function() { 2 $('.directUpload').find("input:file").each(function(i, elem) { 3 var fileInput = $(elem); 4 var form = $(fileInput.parents('form:first')); 5 var submitButton = form.find('input[type="submit"]'); 6 var progressBar = $("<div class='bar'></div>"); 7 var barContainer = $("<div class='progress'></div>").append(progressBar); 8 fileInput.after(barContainer); 9 fileInput.fileupload({ 10 fileInput: fileInput, 11 url: form.data('url'), 12 type: 'POST', 13 autoUpload: false, 14 formData: form.data('form-data'), 15 paramName: 'file', // S3 does not like nested name fields i.e. name="user[avatar_url]" 16 dataType: 'XML', // S3 returns XML if success_action_status is set to 201 17 replaceFileInput: true, 18 acceptFileTypes: /(.|/)(gif|jpe?g|png)$/i, 19 20 add: function(e, data){ 21 if (data.files && data.files[0]) { 22 console.log("called"); 23 var reader = new FileReader(); 24 reader.onload = function(e) { 25 $('.preview').empty(); 26 $('.preview').append($('<img>').attr({// insert preview image 27 src: e.target.result, 28 id: "crop_img", 29 title: data.files[0].name 30 })); 31 $('#crop_img').cropper() // initialize cropper on preview image 32 }; 33 reader.readAsDataURL(data.files[0]); 34 }; 35 36 submitButton.on('click', function(){ 37 // crop のデータを取得 38 $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob){ 39 data.files[0] = new File([blob], data.files[0].name); 40 data.originalFiles[0] = data.files[0]; 41 }) 42 data.submit(); 43 }); 44 }, 45 46 progressall: function (e, data) { 47 var progress = parseInt(data.loaded / data.total * 100, 10); 48 progressBar.css('width', progress + '%') 49 }, 50 51 start: function (e) { 52 submitButton.prop('disabled', true); 53 54 progressBar. 55 css('background', 'black'). 56 css('display', 'block'). 57 css('width', '0%'). 58 text("Loading..."); 59 }, 60 61 done: function(e, data) { 62 submitButton.prop('disabled', false); 63 progressBar.text("Uploading done"); 64 65 // extract key and generate URL from response 66 var key = $(data.jqXHR.responseXML).find("Key").text(); 67 var url = '//' + form.data('host') + '/' + key; 68 69 // create hidden field 70 var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url }) 71 form.append(input); 72 $('.directUpload').submit(); //submit a form 73 }, 74 75 fail: function(e, data) { 76 submitButton.prop('disabled', false); 77 78 progressBar. 79 css("background", "red"). 80 text("Failed"); 81 } 82 }); 83 }); 84}); 85
Ruby
1#new.html.erb 2... 3<%= form_for @post, :url => { :controller => :posts, :action => :create } ,html: { class: "directUpload", data: { 'form-data' => (@s3_direct_post.fields), 'url' => @s3_direct_post.url, 'host' => URI.parse(@s3_direct_post.url).host } } do |f|%> 4 <div class="field" > 5 <%= f.label("アイテム画像(必須)") %> 6 <%= f.file_field :image_name %> 7 8 <div class="preview"><img id="crop_img" /></div> 9 <div class="clear_float"></div> 10 11 <%= f.hidden_field :designer_id, :value => current_user.id %> 12 <div class="clear_float"></div> 13 14 <%= f.label("コメント") %> 15 <%= f.text_area :detail %> 16 17 <%= f.submit("投稿", :id => "_submit") %> 18 <% end %> 19...
どうすれば、トリミング後の画像を、s3にアップすることができるでしょうか?
アドバイスをよろしくお願いいたします。
#試してみたこと
以下のようにコードを書き換えて、コンソールでオンクリックアクション時のdata.originalFiles[0]の中身を確認すると、ちゃんとトリミング後の画像になっていました。
一度submitボタンを押してアップロードが完了した後、もう一度クリックすると、トリミング後の画像がs3にアップされることがわかりました。
なぜ1度目のクリックで行かないのでしょうか…
Javascript
1$(function() { 2 $('.directUpload').find("input:file").each(function(i, elem) { 3 ... 4 submitButton.on('click', function(){ 5 // crop のデータを取得 6 $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob){ 7 data.files[0] = new File([blob], data.files[0].name); 8 data.originalFiles[0] = data.files[0]; 9 }) 10 data.submit(); 11 }); 12 }, 13 14 .... 15 16 done: function(e, data) { 17 ... 18 //アップロード完了時のフォームの提出をキャンセル 19 //$('.directUpload').submit(); //submit a form 20 }, 21 .... 22 23 24 }); 25}); 26
補足情報(FW/ツールのバージョンなど)
Ruby on Rails 5
aws-sdk (3.0.1, 2.11.25, 2.11.3)
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/04/02 00:56