Rails5でCarrerwaveを用いた複数ファイルのアップロード機能を作っております。
既に複数ファイルアップロード機能は実装済みです。
■実現したいこと
フォーム作成でバリデーションに失敗した際に、ファイルデータを保持しておきたいです。
実装はビューでバリデーションに失敗したか否かで、htmlの表示を切り替えるようにしております。
しかし、バリデーション失敗→フォーム再登録でファイル情報が格納されるfile_infoにnullが入ってしまいます。
■モデル情報
・User:親モデル
・Files:個モデル
-カラム情報
file_info:ファイル情報格納用,
file_name:ファイル名格納用,
file_info_cache:キャッシュ情報格納用
UserとFilesは1対多のアソシエーション
■問題点
バリデーション失敗時のビューの@user.files[1].file_infoに値が入っているにもかかわらず、
コントローラーのcreateアクションに渡った際に@user.files[1].file_infoにnullが入ってしまいます。
ファイルのキャッシュ情報はtype=hiddenでコントローラー側に送るようにしております。
html側にうまくデータを紐付けできていないことが問題だとは思うのですが、根本的にどこが間違っているかわからない状況です。
・バリデーション失敗後に表示されたビュー内のデバッグ情報
pry
1[1] pry(#<#<Class:0x00007f9e20452228>>)> @user.files 2=> [#<File:0x00007f9e18f74118 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_name: "">, 3 #<FIle:0x00007f9e2095ace8 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_name: "test">] 4 5 6// バリデーション失敗時のビューではfile_infoの情報が格納されている 7 8[2] pry(#<#<Class:0x00007f9e20452228>>)> @user.files[1].file_info 9=> #<FileUploader:0x00007f9e20959f50 10 @cache_id="1580997255-49160068767576-0071-9156", 11 @cache_storage=#<CarrierWave::Storage::File:0x00007f9e18f57130 @cache_called=nil, @uploader=#<FileUploader:0x00007f9e20959f50 ...>>, 12 @file= 13 #<CarrierWave::SanitizedFile:0x00007f9e209588a8 14 @content=nil, 15 @content_type="image/png", 16 @file="/Users/jasper/Desktop/ruby_workspace/myapp/public/uploads/tmp/1580997255-49160068767576-0071-9156/icon17.png", 17 @original_filename="icon17.png">, 18 @filename="icon17.png", 19 @identifier=nil, 20 @model=#<FIle:0x00007f9e2095ace8 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_name: "test">, 21 @mounted_as=:file_info, 22 @original_filename="icon17.png", 23 @staged=true, 24 @versions={}> 25 26[3] pry(#<UsersController>)> @user.files[1].file_info.retrieve_from_cache! @user.files[1].file_info.cache_name 27=> [:retrieve_versions_from_cache!]
・バリデーション失敗後に表示されたhtml(保存されない)
html
1<div class="form-group row p-2"> 2 <div class="file-group ml-3"> 3 <label for="user_files_attributes_0_ファイル名">ファイル名</label> 4 <input autocomplete="off" class="form-control file_info col-4" data-file="1" name="user[files_attributes][1][file_info_tmp]" placeholder="まずファイル名を入力してね!" type="text"> 5 <input autocomplete="off" class="form-control file_info col-4" data-file="0" name="user[files_attributes][0][file_info_tmp]" placeholder="まずファイル名を入力してね!" style="display: none;" type="text" value="test"> 6 <end></end> 7 <div id="preview"> 8 <div class="dropzone-area"> 9 <label class="dropzone-box" for="" id="fileInput"></label> 10 <div class="btn fa fa-file attached_file mt-2 disabled btn-outline-dark">ファイル添付</div> 11 <div class="input_area"> 12 <input class="upload-file" data-file="1" id="upload-file" name="user[files_attributes][1][file_info]" type="file" style="display: none;"> 13 <input class="upload-file" data-file="0" id="upload-file" name="user[files_attributes][0][file_info]" style="display: none;" type="file"> 14 <end></end> 15 <input id="user_files_attributes_0_file_info_cache" name="user[files_attributes][0][file_info_cache]" type="hidden"> 16 </div> 17 </div> 18 <li data-file="1" id="sp_sell-upload-item" style="list-style: none; margin-right: 20px; margin-top: 5px; margin-bottom: 20px; display: inline-block;"> 19 <div class="sp_sell-upload-file"> 20 <img src="data:image/png;base64,iVBORRK5CYII" width="128" height="128"> 21 </div> 22 <p class="mb-0">test.png</p> 23 <div class="sp_sell-upload-button btn btn-sm btn-outline-danger"> 24 <a class="sp_sell-upload-delete delete" data-file="1" style="cursor:pointer;">削除</a> 25 </div> 26 </li> 27 </div> 28 </div> 29</div>
・バリデーション失敗後のコントローラー(保存されない)
pry
1[1] pry(#<UsersController>)> @user.files 2=> [#<FIle:0x00007f9e20227980 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_info_tmp: "">, 3 #<FIle:0x00007f9e2020fdf8 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_info_tmp: "test">] 4 5[2] pry(#<UsersController>)> @user.files[1].file_info 6=> #<FIleUploader:0x00007f9e1fed9a30 7 @cache_id=nil, 8 @file=nil, 9 @filename=nil, 10 @identifier=nil, 11 @model=#<FIle:0x00007f9e2020fdf8 id: nil, file_info: nil, created_at: nil, updated_at: nil, user: nil, references: nil, user_id: nil, file_info_tmp: "test">, 12 @mounted_as=:file_info, 13 @staged=false, 14 @versions=nil>
■該当するソースコード
View
1- if @user.files.length == 1 2 3 .form-group.row.p-2 4 5 = f.fields_for :files do |p| 6 7 .file-group.ml-3 8 // ファイル名用 9 = p.label :ファイル名 10 = p.text_field :file_name, class: 'form-control file_info col-4', id: 'file-name', placeholder: 'まずファイル名を入力してね!', autocomplete: 'off', 'data-file': 0 11 12 // ファイルインプット用 13 #preview 14 .dropzone-area 15 = p.label :file_info, id: "fileInput", class: "dropzone-box", for: "" do 16 .btn.btn-outline-dark.fa.fa-file.attached_file.disabled.mt-2 17 | ファイル添付 18 .input_area 19 / バリデーション失敗時にファイルが添付されていた場合 20 = p.file_field :file_info, id: "upload-file", class: "upload-file", 'data-file': 0 21 = p.hidden_field :file_info_cache 22 23- else 24 25 .form-group.row.p-2 26 .file-group.ml-3 27 label for="user_files_attributes_0_ファイル名" ファイル名 28 - @user.files.reverse.each_with_index.reverse_each do |file, index| 29 - file_info = file.file_name 30 - if @user.files.length - 1 == index 31 input.form-control.file_info.col-4 autocomplete="off" data-file="#{index}" name="user[files_attributes][#{index}][file_name]" placeholder="まずファイル名を入力してね!" type="text" 32 -else 33 input.form-control.file_info.col-4 autocomplete="off" data-file="#{index}" name="user[files_attributes][#{index}][file_name]" placeholder="まずファイル名を入力してね!" type="text" style=("display: none;") value="#{file_info}" 34 end 35 #preview 36 .dropzone-area 37 label#fileInput.dropzone-box for="" 38 .btn.fa.fa-file.attached_file.mt-2.disabled.btn-outline-dark ファイル添付 39 .input_area 40 = binding.pry 41 - @user.files.reverse.each_with_index.reverse_each do |file_path, index| 42 - if @user.files.length - 1 == index 43 input#upload-file.upload-file data-file="#{index}" name="user[files_attributes][#{index}][file_info]" type="file" 44 - else 45 input#upload-file.upload-file data-file="#{index}" name="user[files_attributes][#{index}][file_info]" type="file" style=("display: none;") 46 end 47 input#user_files_attributes_0_file_info_cache name="user[files_attributes][0][file_info_cache]" type="hidden" 48 49 - @user.files.each_with_index do |file, index| 50 - if index != 0 51 li#sp_sell-upload-item data-file="#{index}" style=("list-style: none; margin-right: 20px; margin-top: 5px; margin-bottom: 20px; display: inline-block;") 52 .sp_sell-upload-file 53 - file_url = "data:" + file.file_info.content_type + ";base64," + Base64.encode64(File.read(file.file_info.path)) 54 = file_tag file_url, :size => '128x128' 55 p.mb-0 = file.file_info.model.file_name + "." + file.file_info.file.original_filename.split(".")[-1] 56 .sp_sell-upload-button.btn.btn-sm.btn-outline-danger 57 a.sp_sell-upload-delete.delete data-file="#{index}" style="cursor:pointer;" 削除
Controller
1def create 2 3 @user = User.new(user_params) 4 5 if @user.files.length > 1 6 @user.files[0].destroy 7 end 8 9 binding.pry 10 11 if @user.save 12 13 else 14 respond_to do |format| 15 render_flg = 1 16 format.html { render action: 'new' } 17 end 18 end 19 20 21 22 redirect_to @user, notice: "「#{reg_name}」様の予約を登録しました。" 23 24end 25 26def user_params 27 params.require(:user).permit( 28 files_attributes: [ 29 :file_info, 30 :file_info_cache, 31 :file_name 32 ] 33) 34end
問題点わかりましたらご教示いただければ幸いです。
あなたの回答
tips
プレビュー