前提・実現したいこと
Rails5を使って、ユーザーが画像を選択し、自由にトリミングした上で投稿できる機能を実装中です。
処理を高速化させるために、jQuery file-uploadを使用して、サーバーサイドではなくクライアントサイドから直接s3にアップさせています。
投稿作成画面でファイルを選択し直すと、その回数分、同じ投稿が複数作られてしまう問題が発生しており、解決したいです。
発生している問題・エラーメッセージ
アップロード及び投稿の作成はうまくいくのですが、画像を選択し直すと、その数だけ同じ投稿が複製されてしまいます。
選択し直すたびに、createアクションへのリクエストが発生しているのかと考えたのですが、いまいち原因が判然としません。
ご助言をいただきたいです。
該当のソースコード
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 singleFileUploads: false, 20 21 add: function(e, data){ 22 if (data.files && data.files[0]) { 23 24 var reader = new FileReader(); 25 reader.onload = function(e) { 26 $('.preview').empty(); 27 $('.preview').append($('<img>').attr({// insert preview image 28 src: e.target.result, 29 id: "crop_img", 30 title: data.files[0].name 31 })); 32 $('#crop_img').cropper() // initialize cropper on preview image 33 }; 34 reader.readAsDataURL(data.files[0]); 35 }; 36 37 submitButton.on('click', function(){ 38 $('form').submit(function(){ 39 return false; 40 }); 41 // crop のデータを取得 42 $('#crop_img').cropper('getCroppedCanvas').toBlob(function (blob){ 43 data.files[0] = new File([blob], data.files[0].name); 44 data.originalFiles[0] = data.files[0]; 45 data.submit(); 46 }) 47 }); 48 }, 49... 50 done: function(e, data) { 51 progressBar.text("Uploading done"); 52 53 // extract key and generate URL from response 54 var key = $(data.jqXHR.responseXML).find("Key").text(); 55 var url = '//' + form.data('host') + '/' + key; 56 57 // create hidden field 58 var input = $("<input />", { type:'hidden', name: fileInput.attr('name'), value: url }); 59 form.append(input); 60 $('form').off('submit'); 61 //and submit again 62 $('.directUpload').submit(); 63 }, 64... 65 66 }); 67 }); 68}); 69
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 8 <div class="preview"><img id="crop_img" /></div> 9 <div class="clear_float"></div> 10 11 <%= f.hidden_field :user_id, :value => current_user.id %> 12 <div class="clear_float"></div> 13 14 <%= f.label("コメント") %> 15 <%= f.text_area :detail %> 16 17 <%= f.submit("投稿") %> 18 <% end %> 19...
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 :detail 12 ) 13 @post = Post.new(post) 14 if @post.save 15 flash[:notice]="投稿しました" 16 redirect_to("/") 17 else 18 render("posts/new") 19 end 20 end 21... 22end
#試してみたこと
changeコールバックを追加して、画像が選択され直すたびに、formをリセットしようとしましたが、これだと新しく選択した画像もリセットされてしまい投稿が作成できませんでした。
javascript
1$(function() { 2 $('.directUpload').find("input:file").each(function(i, elem) { 3 ... 4 5 add: function(e, data){ 6 ... 7 }, 8 9 change: function(e, data){ 10 $('form').reset(); 11 } 12 13 done: function(e, data) { 14 ... 15 }, 16... 17 18 }); 19 }); 20});
【追記】クリアボタンを追加して、フォームとファイルデータをリセットするように試みましたが、変わりありませんでした。
javascript
1... 2add: function(e, data){ 3 if (data.files && data.files[0]) { 4 var reader = new FileReader(); 5 reader.onload = function(e) { 6 $('.preview').empty(); 7 $('.preview').append($('<img>').attr({// insert preview image 8 src: e.target.result, 9 id: "crop_img", 10 title: data.files[0].name 11 })); 12 $('#crop_img').cropper() // initialize cropper on preview image 13 }; 14 reader.readAsDataURL(data.files[0]); 15 $('#clear').show(); //ファイルが加えられるとクリアボタンを表示 16 }; 17 //クリアボタンをクリックすると、formとファイルをリセット 18 $('#clear').click(function() { 19 $('#image').val(''); 20 $('.preview').empty(); 21 $('form').reset(); 22 $(this).hide(); 23 }); 24...
html
1<%= 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|%> 2 <div class="field" > 3 <%= f.label("アイテム画像(必須)") %> 4 <%= f.file_field :image_name, accept: 'image/jpg,image/jpeg,image/png,image/gif', id: 'image' %> 5 6 <input type="button" id="clear" value="画像を選び直す"> 7 8 ... 9 <%= f.submit("投稿") %> 10 <% end %>
補足情報(FW/ツールのバージョンなど)
Ruby on Rails 5
jQuer-file-upload
Cropper.js
あなたの回答
tips
プレビュー