前提・実現したいこと
Rails5を使って、ユーザーが画像を選択し、自由にトリミングした上で投稿できる機能を実装中です。
参考:[Javascript] Rails5でユーザーがトリミングした画像を、S3に直接アップロードしたい
画像のアップロードは問題なくできるのですが、アップした画像をviewで表示する際に問題が発生しています。
発生している問題・エラーメッセージ
画像を表示させようとすると、以下のようなエラーが出ます。
The asset "" is not present in the asset pipeline.
postオブジェクトの中身をのぞいてみると、image_nameの部分が、"#<ActionDispatch::Http::UploadedFile:0x00007fe3122..."
になっています。
本来ならば、ここには、"//my-development.s3.amazonaws.com/uploads/...
のような、s3上の画像を参照するURLを入れておきたいです。
画像をトリミング処理しない場合は、問題なくこのURLが入力され、表示できるのですが、トリミングを行うとこの値が渡されてしまいます。
デバックしてみたところ、以下のjavascriptコードの、fileUpload
関数内のdone
コールバックが呼ばれていないようです。
どうすればこのコールバックがきちんと呼ばれるようになるか、アドバイスをお願いいたします。
【追記】s3へのアップロードが完了しないまま、ページが遷移してしまうことが原因のようです。submitボタンをクリックした際に、js側でs3へのアップロードを完了させたあとに、フォームをサーバーに提出させるには、どうすればいいでしょうか?
→**【追記2】formのsubmitを一度中断し、アップロード完了後に再開させるという処理を思いつきました。**中断はできるのですが、再開がうまくできません。「試したこと」欄に詳述するので、アドバイスいただきたいです。
該当のソースコード
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: false, 18 acceptFileTypes: /(.|/)(gif|jpe?g|png)$/i, 19 20 add: function(e, data){ 21 if (data.files && data.files[0]) { 22 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 data.submit(); 42 }) 43 }); 44 }, 45... 46 done: function(e, data) { 47 progressBar.text("Uploading done"); 48 49 // extract key and generate URL from response 50 var key = $(data.jqXHR.responseXML).find("Key").text(); 51 var url = '//' + form.data('host') + '/' + key; 52 53 // create hidden field 54 $("#post_remote_image_url").val(url); //hidden_field内のremote_image_urlの値にURLを入れる 55 var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url }); 56 form.append(input); 57 }, 58... 59 60 }); 61 }); 62}); 63
html
1... 2 <%= 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|%> 3 <div class="field" > 4 <%= f.label("アイテム画像(必須)") %> 5 <%= f.file_field :image_name %> 6 7 <%= f.hidden_field :remote_image_url %> 8 9 <div class="preview"><img id="crop_img" /></div> 10 <div class="clear_float"></div> 11 12 <%= f.hidden_field :user_id, :value => current_user.id %> 13 <div class="clear_float"></div> 14 15 <%= f.label("コメント") %> 16 <%= f.text_area :detail %> 17 18 <%= f.submit("投稿") %> 19 <% end %> 20...
ruby
1class PostsController < ApplicationController 2 ... 3 def new 4 @post = Post.new 5 end 6 7 def create 8 post = params.require(:post).permit( 9 :user_id, 10 :image_name, 11 :remote_image_url; 12 :detail 13 ) 14 @post = Post.new(post) 15 if @post.save 16 flash[:notice]="投稿しました" 17 redirect_to("/") 18 else 19 render("posts/new") 20 end 21 end 22... 23end
#試してみたこと
submitボタンがクリックされた際に、一度formのsubmitを中断
→画像のアップロード完了後に再開、という手段を試みました。
以下のようにコードを修正し、中断させることには成功しましたが、画像のアップロード完了後にformのsubmitをもう一度有効化することができていません。
何故有効化できないのでしょうか?ご意見をいただきたいです。
javascript
1$(function() { 2 ... 3 add: function(e, data){ 4 ... 5 submitButton.on('click', function(){ 6 //一度submitを中断させる 7 $('form').submit(function(){ 8 return false; 9 }); 10 // crop のデータを取得 11 $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob){ 12 data.files[0] = new File([blob], data.files[0].name); 13 data.originalFiles[0] = data.files[0]; 14 data.submit(); 15 }) 16 }); 17 }, 18 19 ... 20 21 done: function(e, data) { 22 submitButton.prop('disabled', false); 23 progressBar.text("Uploading done"); 24 25 // extract key and generate URL from response 26 var key = $(data.jqXHR.responseXML).find("Key").text(); 27 var url = '//' + form.data('host') + '/' + key; 28 29 // create hidden field 30 var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url }) 31 form.append(input); 32 //submitを再開させたいが、うまくいきません 33 $('form').submit(function(){ 34 return true; 35 }); 36 $('.directUpload').submit(); 37 console.log("upload done!!") //このログが表示されるため、doneコールバックはきちんと呼ばれています。 38 }, 39 40 fail: function(e, data) { 41 submitButton.prop('disabled', false); 42 43 progressBar. 44 css("background", "red"). 45 text("Failed"); 46 } 47 }); 48 }); 49}); 50
補足情報(FW/ツールのバージョンなど)
Ruby on Rails 5
jQuer-file-upload
Cropper.js
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。