From 77528bf27940441206beae95fc6902168707115f Mon Sep 17 00:00:00 2001 From: Shana Moore Date: Wed, 30 Oct 2024 08:51:54 -0700 Subject: [PATCH] [i858] - Enables chunked uploads for improved file upload reliability (#982) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [i858] - Enables chunked uploads for improved file upload reliability and efficiency Issue: - https://github.com/scientist-softserv/adventist_knapsack/issues/858 Chunked uploads allow large files to be uploaded in smaller parts, addressing common issues with file size limits, network interruptions, and server resource management. This change supports smoother, more reliable uploads for large files in Bulkrax. * Adds Hyrax file uploader to bagit, and xml partial * ♻️ Move common code into a shared partial * 🎁 Adds custom js validations to add/remove required attr * Update importers_controller_spec.rb * remove upperbound for Hyrax version * bump versions to make bundling on arm processors work again * ✅ adds Hyrax::UploadedFile context to importers controller spec * ♻️ Move Bulkrax uploader logic to importers.js and ensure conditional initialization - Moved Bulkrax file upload logic from bulkrax.js to importers.js to consolidate related logic - Added conditional check to initialize uploader only if `hyraxUploader` is defined as a function - Ensured toggle of 'required' attribute based on uploaded file presence for import form consistency * re add deleted comments --------- Co-authored-by: Rob Kaufman --- .gitignore | 1 + Gemfile | 4 + app/assets/javascripts/bulkrax/bulkrax.js | 16 +- .../javascripts/bulkrax/importers.js.erb | 233 ++++++++++-------- .../bulkrax/importers_controller.rb | 21 +- .../bulkrax/importers/_bagit_fields.html.erb | 13 +- .../bulkrax/importers/_csv_fields.html.erb | 22 +- .../bulkrax/importers/_file_uploader.html.erb | 37 +++ .../bulkrax/importers/_xml_fields.html.erb | 14 +- .../bulkrax/importers_controller_spec.rb | 36 +++ spec/rails_helper.rb | 2 + 11 files changed, 272 insertions(+), 127 deletions(-) create mode 100644 app/views/bulkrax/importers/_file_uploader.html.erb diff --git a/.gitignore b/.gitignore index 23f1e0829..c1b3dc81e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ spec/test_app/log/*.log spec/test_app/tmp/ tmp/** *~undo-tree~ +/vendor diff --git a/Gemfile b/Gemfile index 2f857495d..f35b4129f 100644 --- a/Gemfile +++ b/Gemfile @@ -32,6 +32,10 @@ group :development, :test do gem 'sqlite3', '~> 1.4' end +group :test do + gem 'rails-controller-testing' +end + group :lint do gem 'bixby' gem 'rubocop-factory_bot', require: false diff --git a/app/assets/javascripts/bulkrax/bulkrax.js b/app/assets/javascripts/bulkrax/bulkrax.js index 006ce8205..e7b298ed0 100644 --- a/app/assets/javascripts/bulkrax/bulkrax.js +++ b/app/assets/javascripts/bulkrax/bulkrax.js @@ -5,18 +5,20 @@ $(document).on('turbolinks:load ready', function() { $('button#err_toggle').click(function() { $('#error_trace').toggle(); }); + $('button#fm_toggle').click(function() { $('#field_mapping').toggle(); }); + $('#bulkraxItemModal').on('show.bs.modal', function (event) { - var button = $(event.relatedTarget) // Button that triggered the modal - var recipient = button.data('entry-id') // Extract info from data-* attributes + var button = $(event.relatedTarget); // Button that triggered the modal + var recipient = button.data('entry-id'); // Extract info from data-* attributes // If necessary, you could initiate an AJAX request here (and then do the updating in a callback). // Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead. - var modal = $(this) + var modal = $(this); modal.find('a').each(function() { - this.href = this.href.replace(/\d+\?/, recipient + '?') - }) - return true - }) + this.href = this.href.replace(/\d+\?/, recipient + '?'); + }); + return true; + }); }); diff --git a/app/assets/javascripts/bulkrax/importers.js.erb b/app/assets/javascripts/bulkrax/importers.js.erb index e254c60e2..de11ecdd3 100644 --- a/app/assets/javascripts/bulkrax/importers.js.erb +++ b/app/assets/javascripts/bulkrax/importers.js.erb @@ -2,205 +2,240 @@ // All this logic will automatically be available in application.js. function prepBulkrax(event) { - var refresh_button = $('.refresh-set-source') - var base_url = $('#importer_parser_fields_base_url') - var initial_base_url = base_url.val() - var file_path_value = $('#importer_parser_fields_import_file_path').val() - handleFileToggle(file_path_value) + var refresh_button = $('.refresh-set-source'); + var base_url = $('#importer_parser_fields_base_url'); + var initial_base_url = base_url.val(); + var file_path_value = $('#importer_parser_fields_import_file_path').val(); + handleFileToggle(file_path_value); + + // Initialize the uploader only if hyraxUploader is defined + if (typeof $.fn.hyraxUploader === 'function') { + // Initialize the uploader + $('.fileupload-bulkrax').hyraxUploader({ maxNumberOfFiles: 1 }); + + // Function to toggle 'required' attribute based on uploaded files + function toggleRequiredAttribute() { + const fileInput = $('#addfiles'); + const uploadedFilesTable = $('.fileupload-bulkrax tbody.files'); + + if (uploadedFilesTable.find('tr.template-download').length > 0) { + // Remove 'required' if there are uploaded files + fileInput.removeAttr('required'); + } else { + // Add 'required' if no uploaded files + fileInput.attr('required', 'required'); + } + } + + // Check the required attribute when a file is added or removed + $('#addfiles').on('change', function() { + toggleRequiredAttribute(); + }); + + // Also check when an upload completes or is canceled + $('.fileupload-bulkrax').on('fileuploadcompleted fileuploaddestroyed', function() { + toggleRequiredAttribute(); + }); + + // Ensure 'required' is only added if there are no files on form reset + $('#file-upload-cancel-btn').on('click', function() { + $('#addfiles').attr('required', 'required'); + $('#addfiles').val(''); // Clear file input to ensure 'required' behavior resets + }); + + // Initial check in case files are already uploaded + toggleRequiredAttribute(); + } // handle refreshing/loading of external sets via button click $('body').on('click', '.refresh-set-source', function(e) { - e.preventDefault() + e.preventDefault(); - external_set_select = $("#importer_parser_fields_set") - handleSourceLoad(refresh_button, base_url, external_set_select) - }) + external_set_select = $("#importer_parser_fields_set"); + handleSourceLoad(refresh_button, base_url, external_set_select); + }); // handle refreshing/loading of external sets via blur event for the base_url field $('body').on('blur', '#importer_parser_fields_base_url', function(e) { - e.preventDefault() + e.preventDefault(); // retrieve the latest base_url - base_url = $('#importer_parser_fields_base_url') + base_url = $('#importer_parser_fields_base_url'); // ensure we don't make another query if the value is the same -- this can be forced by clicking the refresh button if (initial_base_url != base_url.val()) { - external_set_select = $("#importer_parser_fields_set") - handleSourceLoad(refresh_button, base_url, external_set_select) - initial_base_url = base_url.val() + external_set_select = $("#importer_parser_fields_set"); + handleSourceLoad(refresh_button, base_url, external_set_select); + initial_base_url = base_url.val(); } - }) + }); // hide and show correct parser fields depending on klass setting $('body').on('change', '#importer_parser_klass', function(e) { - handleParserKlass() - }) - handleParserKlass() + handleParserKlass(); + }); + handleParserKlass(); // observer for cloud files being added var form = document.getElementById('new_importer'); if (form == null) { - var form = document.getElementsByClassName('edit_importer')[0]; + form = document.getElementsByClassName('edit_importer')[0]; } + // only setup the observer on the new and edit importer pages if (form != null) { var config = { childList: true, attributes: true }; var callback = function(mutationsList) { for(var mutation of mutationsList) { - if (mutation.type == 'childList') { browseButton = document.getElementById('browse'); - var exp = /selected_files\[[0-9]*\]\[url\]/ + var exp = /selected_files\[[0-9]*\]\[url\]/; for (var node of mutation.addedNodes) { if (node.attributes != undefined) { - var name = node.attributes.name.value + var name = node.attributes.name.value; if (exp.test(name)) { browseButton.innerHTML = 'Cloud Files Added'; browseButton.style.backgroundColor = 'green'; - browseButton.after(document.createElement("br"), node.value.toString()) + browseButton.after(document.createElement("br"), node.value.toString()); } } } } } }; - var observer = new MutationObserver (callback); - observer.observe (form, config); + var observer = new MutationObserver(callback); + observer.observe(form, config); } } function handleFileToggle(file_path) { if (file_path === undefined || file_path.length === 0) { - $('#file_path').hide() - $('#file_upload').hide() - $('#cloud').hide() - $('#existing_options').hide() - $('#file_path input').attr('required', null) - $('#file_upload input').attr('required', null) + $('#file_path').hide(); + $('#file_upload').hide(); + $('#cloud').hide(); + $('#existing_options').hide(); + $('#file_path input').attr('required', null); + $('#file_upload input').attr('required', null); } else { - $('#file_path').show() - $('#file_upload').hide() - $('#cloud').hide() - $('#existing_options').hide() - $('#file_path input').attr('required', 'required') - $('#file_upload input').attr('required', null) - $('#importer_parser_fields_file_style_specify_a_path_on_the_server').attr('checked', true) + $('#file_path').show(); + $('#file_upload').hide(); + $('#cloud').hide(); + $('#existing_options').hide(); + $('#file_path input').attr('required', 'required'); + $('#file_upload input').attr('required', null); + $('#importer_parser_fields_file_style_specify_a_path_on_the_server').attr('checked', true); } $('#importer_parser_fields_file_style_upload_a_file').click(function(e){ - $('#file_path').hide() - $('#file_upload').show() - $('#cloud').hide() - $('#existing_options').hide() - $('#file_path input').attr('required', null) - $('#file_upload input').attr('required', 'required') - }) + $('#file_path').hide(); + $('#file_upload').show(); + $('#cloud').hide(); + $('#existing_options').hide(); + $('#file_path input').attr('required', null); + $('#file_upload input').attr('required', 'required'); + }); $('#importer_parser_fields_file_style_specify_a_path_on_the_server').click(function(e){ - $('#file_path').show() - $('#file_upload').hide() - $('#cloud').hide() - $('#existing_options').hide() - $('#file_path input').attr('required', 'required') - $('#file_upload input').attr('required', null) - }) + $('#file_path').show(); + $('#file_upload').hide(); + $('#cloud').hide(); + $('#existing_options').hide(); + $('#file_path input').attr('required', 'required'); + $('#file_upload input').attr('required', null); + }); $('#importer_parser_fields_file_style_add_cloud_file').click(function(e){ - $('#file_path').hide() - $('#file_upload').hide() - $('#cloud').show() - $('#existing_options').hide() - $('#file_path input').attr('required', null) - $('#file_upload input').attr('required', null) - }) + $('#file_path').hide(); + $('#file_upload').hide(); + $('#cloud').show(); + $('#existing_options').hide(); + $('#file_path input').attr('required', null); + $('#file_upload input').attr('required', null); + }); $('#importer_parser_fields_file_style_existing_entries').click(function(e){ - $('#file_path').hide() - $('#file_upload').hide() - $('#cloud').hide() - $('#existing_options').show() - $('#file_path input').attr('required', null) - $('#file_upload input').attr('required', null) - }) - + $('#file_path').hide(); + $('#file_upload').hide(); + $('#cloud').hide(); + $('#existing_options').show(); + $('#file_path input').attr('required', null); + $('#file_upload input').attr('required', null); + }); } function handleParserKlass() { <% Bulkrax.parsers.map{ |p| p[:partial]}.uniq.each do |partial| %> if($('.<%= partial %>').length > 0) { - window.<%= partial %> = $('.<%= partial %>').detach() + window.<%= partial %> = $('.<%= partial %>').detach(); } <% end %> - var parser_klass = $("#importer_parser_klass option:selected") + var parser_klass = $("#importer_parser_klass option:selected"); if(parser_klass.length > 0 && parser_klass.data('partial') && parser_klass.data('partial').length > 0) { - $('.parser_fields').append(window[parser_klass.data('partial')]) + $('.parser_fields').append(window[parser_klass.data('partial')]); } - handleBrowseEverything() - var file_path_value = $('#importer_parser_fields_import_file_path').val() - handleFileToggle(file_path_value) + handleBrowseEverything(); + var file_path_value = $('#importer_parser_fields_import_file_path').val(); + handleFileToggle(file_path_value); } function handleBrowseEverything(){ - var button = $("button[data-toggle='browse-everything']") + var button = $("button[data-toggle='browse-everything']"); if(button.length == 0) { return; } button.browseEverything({ route: button.data('route'), target: button.data('target') }).done(function(data) { var evt = { isDefaultPrevented: function() { return false; } }; - $('.ev-browser.show').removeClass('show') + $('.ev-browser.show').removeClass('show'); if($('#fileupload').length > 0) { - var files = $.map(data, function(d) { return { name: d.file_name, size: d.file_size, id: d.url } }); + var files = $.map(data, function(d) { return { name: d.file_name, size: d.file_size, id: d.url }; }); $.blueimp.fileupload.prototype.options.done.call($('#fileupload').fileupload(), evt, { result: { files: files }}); } - return true - // User has submitted files; data contains an array of URLs and their options + return true; }).cancel(function() { - $('.ev-browser.show').removeClass('show') - // User cancelled the browse operation + $('.ev-browser.show').removeClass('show'); }).fail(function(status, error, text) { - $('.ev-browser.show').removeClass('show') - // URL retrieval experienced a technical failure + $('.ev-browser.show').removeClass('show'); }); } function handleSourceLoad(refresh_button, base_url, external_set_select) { if (base_url.val() == "") { // ignore empty base_url value - return + return; } - var initial_button_text = refresh_button.html() + var initial_button_text = refresh_button.html(); - refresh_button.html('Refreshing...') - refresh_button.attr('disabled', true) + refresh_button.html('Refreshing...'); + refresh_button.attr('disabled', true); $.post('/importers/external_sets', { base_url: base_url.val(), }, function(res) { if (!res.error) { - genExternalSetOptions(external_set_select, res.sets) // sets is [[name, spec]...] + genExternalSetOptions(external_set_select, res.sets); } else { - setError(external_set_select, res.error) + setError(external_set_select, res.error); } - refresh_button.html(initial_button_text) - refresh_button.attr('disabled', false) - }) + refresh_button.html(initial_button_text); + refresh_button.attr('disabled', false); + }); } function genExternalSetOptions(selector, sets) { - out = '' + out = ''; out += sets.map(function(set) { - return '' - }) + return ''; + }); - selector.html(out) - selector.attr('disabled', false) + selector.html(out); + selector.attr('disabled', false); } function setError(selector, error) { - selector.html('') - selector.attr('disabled', true) + selector.html(''); + selector.attr('disabled', true); } -$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax}) +$(document).on({'ready': prepBulkrax, 'turbolinks:load': prepBulkrax}); diff --git a/app/controllers/bulkrax/importers_controller.rb b/app/controllers/bulkrax/importers_controller.rb index 2fe5c4704..d088fdb15 100644 --- a/app/controllers/bulkrax/importers_controller.rb +++ b/app/controllers/bulkrax/importers_controller.rb @@ -78,11 +78,13 @@ def edit # POST /importers # rubocop:disable Metrics/MethodLength + # rubocop:disable Metrics/AbcSize def create # rubocop:disable Style/IfInsideElse if api_request? return return_json_response unless valid_create_params? end + uploads = Hyrax::UploadedFile.find(params[:uploaded_files]) if params[:uploaded_files].present? file = file_param cloud_files = cloud_params @@ -93,7 +95,7 @@ def create # on a new import otherwise it only gets updated during the update path @importer.parser_fields['update_files'] = true if params[:commit] == 'Create and Import' if @importer.save - files_for_import(file, cloud_files) + files_for_import(file, cloud_files, uploads) if params[:commit] == 'Create and Import' Bulkrax::ImporterJob.send(@importer.parser.perform_method, @importer.id) render_request('Importer was successfully created and import has been queued.') @@ -112,6 +114,7 @@ def create end # rubocop:enable Style/IfInsideElse end + # rubocop:enable Metrics/AbcSize # PATCH/PUT /importers/1 # # @todo refactor so as to not need to disable rubocop @@ -120,7 +123,7 @@ def update if api_request? return return_json_response unless valid_update_params? end - + uploads = Hyrax::UploadedFile.find(params[:uploaded_files]) if params[:uploaded_files].present? file = file_param cloud_files = cloud_params @@ -128,7 +131,7 @@ def update field_mapping_params if params[:importer][:parser_fields].present? if @importer.update(importer_params) - files_for_import(file, cloud_files) unless file.nil? && cloud_files.nil? + files_for_import(file, cloud_files, uploads) # do not perform the import unless params[:commit] == 'Update Importer' set_files_parser_fields @@ -218,8 +221,9 @@ def export_errors private - def files_for_import(file, cloud_files) - return if file.blank? && cloud_files.blank? + def files_for_import(file, cloud_files, uploads) + return if file.blank? && cloud_files.blank? && uploads.blank? + @importer[:parser_fields]['import_file_path'] = @importer.parser.write_import_file(file) if file.present? if cloud_files.present? @importer[:parser_fields]['cloud_file_paths'] = cloud_files @@ -229,6 +233,13 @@ def files_for_import(file, cloud_files) target = @importer.parser.retrieve_cloud_files(cloud_files, @importer) @importer[:parser_fields]['import_file_path'] = target if target.present? end + + if uploads.present? + uploads.each do |upload| + @importer[:parser_fields]['import_file_path'] = @importer.parser.write_import_file(upload.file.file) + end + end + @importer.save end diff --git a/app/views/bulkrax/importers/_bagit_fields.html.erb b/app/views/bulkrax/importers/_bagit_fields.html.erb index 6e7bbd41a..f52c20227 100644 --- a/app/views/bulkrax/importers/_bagit_fields.html.erb +++ b/app/views/bulkrax/importers/_bagit_fields.html.erb @@ -41,9 +41,16 @@

File upload and Cloud File upload must be a Zip file containing a single BagIt Bag, or a folder containing multiple BagIt Bags.

The Server Path can point to a BagIt Bag, a folder containing BagIt Bags, or a zip file containing either.

- <%= fi.input :file_style, collection: ['Upload a File', 'Specify a Path on the Server', 'Add Cloud File'], as: :radio_buttons, label: false %> +<%= fi.input :file_style, + collection: ['Upload a File', 'Specify a Path on the Server'] + + (defined?(::Hyrax) && Hyrax.config.browse_everything? ? ['Add Cloud File'] : []), + as: :radio_buttons, label: false %>
- <%= fi.input 'file', as: :file, input_html: {accept: 'application/zip'} %>
+ <% if defined?(::Hyrax) %> + <%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'application/zip' %> + <% else %> + <%= fi.input 'file', as: :file, input_html: {accept: 'application/zip'} %>
+ <% end %>
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %> @@ -53,4 +60,4 @@ <%= render 'browse_everything', form: form %> <% end %>
- + \ No newline at end of file diff --git a/app/views/bulkrax/importers/_csv_fields.html.erb b/app/views/bulkrax/importers/_csv_fields.html.erb index fba5ce0eb..eada5933f 100644 --- a/app/views/bulkrax/importers/_csv_fields.html.erb +++ b/app/views/bulkrax/importers/_csv_fields.html.erb @@ -1,5 +1,4 @@
- <%= fi.input :visibility, label: 'Default Visibility', collection: [ @@ -11,7 +10,6 @@ input_html: { class: 'form-control' }, hint: 'If your CSV includes the visibility field, it will override the default setting.' %> - <% if defined?(::Hyrax) %> <% rights_statements = Hyrax.config.rights_statement_service_class.new %> <%= fi.input :rights_statement, @@ -24,26 +22,32 @@ %> <%= fi.input :override_rights_statement, as: :boolean, hint: 'If checked, always use the selected rights statment. If unchecked, use rights or rights_statement from the record and only use the provided value if dc:rights is blank.', input_html: { checked: (importer.parser_fields['override_rights_statement'] == "1") } %> <% end %> -

Add CSV File to Import:

+

Add CSV or ZIP File to Import:

<%# accept a single file upload; data files and bags will need to be added another way %> - <% file_style_list = ['Upload a File', 'Specify a Path on the Server'] %> <% file_style_list << 'Existing Entries' unless importer.new_record? %> <%= fi.input :file_style, collection: file_style_list, as: :radio_buttons, label: false %> +
- <%= fi.input 'file', as: :file, input_html: { accept: 'text/csv,application/zip,application/gzip' } %>
+ <% if defined?(::Hyrax) %> + <%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'text/csv,application/zip,application/gzip' %> + <% else %> + <%= fi.input 'file', as: :file, input_html: { accept: 'text/csv,application/zip,application/gzip' } %>
+ <% end %>
+
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
+
<%= fi.collection_check_boxes :entry_statuses, [['Failed'], ['Pending'], ['Skipped'], ['Deleted'], ['Complete']], :first, :first %>
- + <% if defined?(::Hyrax) && Hyrax.config.browse_everything? %> -

Add Files to Import:

-

Choose files to upload. The filenames must be unique, and the filenames must be referenced in a column called 'file' in the accompanying CSV file.

+

Add Files to Import:

+

Choose files to upload. The filenames must be unique, and the filenames must be referenced in a column called 'file' in the accompanying CSV file.

<%= render 'browse_everything', form: form %> <% end %>
-
+ \ No newline at end of file diff --git a/app/views/bulkrax/importers/_file_uploader.html.erb b/app/views/bulkrax/importers/_file_uploader.html.erb new file mode 100644 index 000000000..8d1b65751 --- /dev/null +++ b/app/views/bulkrax/importers/_file_uploader.html.erb @@ -0,0 +1,37 @@ +
+ + +
+
+
+
+ + +
+ + +
+
+
+
+
+
+
+
+
 
+
+
+
+
+
+ Drop files here to upload +
+ <%= render 'hyrax/uploads/js_templates' %> +
diff --git a/app/views/bulkrax/importers/_xml_fields.html.erb b/app/views/bulkrax/importers/_xml_fields.html.erb index e77fb4d5c..d5cd2c774 100644 --- a/app/views/bulkrax/importers/_xml_fields.html.erb +++ b/app/views/bulkrax/importers/_xml_fields.html.erb @@ -47,16 +47,22 @@

File upload and Cloud File upload MUST be a either a single XML file (for metadata only import) OR a Zip file containing the XML files and data files, each in a separate folder.

The Server Path can point to a folder containing XML files and data files to import, or direct to the XML file itself.

- <%= fi.input :file_style, collection: ['Upload a File', 'Specify a Path on the Server', 'Add Cloud File'], as: :radio_buttons, label: false %> +<%= fi.input :file_style, + collection: ['Upload a File', 'Specify a Path on the Server'] + + (defined?(::Hyrax) && Hyrax.config.browse_everything? ? ['Add Cloud File'] : []), + as: :radio_buttons, label: false %>
- <%= fi.input 'file', as: :file, input_html: {accept: ['application/zip', 'application/xml']} %>
+ <% if defined?(::Hyrax) %> + <%= render 'bulkrax/importers/file_uploader', accepted_file_types: 'application/zip,application/xml' %> + <% else %> + <%= fi.input 'file', as: :file, input_html: {accept: ['application/zip', 'application/xml']} %>
+ <% end%>
<%= fi.input :import_file_path, as: :string, input_html: { value: importer.parser_fields['import_file_path'] } %>
<% if defined?(::Hyrax) && Hyrax.config.browse_everything? %> - <%= render 'browse_everything', form: form %> <% end %>
- + \ No newline at end of file diff --git a/spec/controllers/bulkrax/importers_controller_spec.rb b/spec/controllers/bulkrax/importers_controller_spec.rb index 569360c55..9d3adea8f 100644 --- a/spec/controllers/bulkrax/importers_controller_spec.rb +++ b/spec/controllers/bulkrax/importers_controller_spec.rb @@ -131,6 +131,24 @@ def current_user post :create, params: { importer: valid_attributes, commit: 'Create and Validate' }, session: valid_session end end + + let(:user) { FactoryBot.create(:user) } + let(:file) { fixture_file_upload('./spec/fixtures/csv/ok.csv') } + let(:uploaded_file) { Hyrax::UploadedFile.create(file: file, user: user) } + + context 'with file uploads' do + it 'assigns uploaded files correctly during creation' do + post :create, params: { importer: valid_attributes, uploaded_files: [uploaded_file.id] }, session: valid_session + expect(assigns(:importer).parser_fields['import_file_path']).to be_present + end + + it 'assigns uploaded files correctly during update' do + importer = Importer.create! valid_attributes + put :update, params: { id: importer.to_param, importer: valid_attributes, uploaded_files: [uploaded_file.id] }, session: valid_session + importer.reload + expect(importer.parser_fields['import_file_path']).to be_present + end + end end describe 'PUT #update' do @@ -165,6 +183,24 @@ def current_user expect(response).to be_successful end end + + let(:user) { FactoryBot.create(:user) } + let(:file) { fixture_file_upload('./spec/fixtures/csv/ok.csv') } + let(:uploaded_file) { Hyrax::UploadedFile.create(file: file, user: user) } + + context 'with file uploads' do + it 'assigns uploaded files correctly during creation' do + post :create, params: { importer: valid_attributes, uploaded_files: [uploaded_file.id] }, session: valid_session + expect(assigns(:importer).parser_fields['import_file_path']).to be_present + end + + it 'assigns uploaded files correctly during update' do + importer = Importer.create! valid_attributes + put :update, params: { id: importer.to_param, importer: valid_attributes, uploaded_files: [uploaded_file.id] }, session: valid_session + importer.reload + expect(importer.parser_fields['import_file_path']).to be_present + end + end end describe 'PUT #continue' do diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 7227d4b57..d9f8d311c 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -11,6 +11,8 @@ # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? require 'rspec/rails' +require 'rails-controller-testing' +Rails::Controller::Testing.install # Add additional requires below this line. Rails is not loaded until this point! FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories')