From 89a8ebbcd7910442d270d140e36312aecf1e6215 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 00:41:15 -0800 Subject: [PATCH 1/7] Thats it, Ive had enough. we need status_message as a column on entry. Today is the day --- app/models/bulkrax/importer.rb | 12 ++++-------- app/models/bulkrax/status.rb | 6 +++++- app/models/concerns/bulkrax/status_info.rb | 3 +++ bulkrax.gemspec | 1 + .../20240208005801_denormalize_status_message.rb | 7 +++++++ lib/bulkrax.rb | 1 + lib/tasks/bulkrax_tasks.rake | 13 +++++++++++++ 7 files changed, 34 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20240208005801_denormalize_status_message.rb diff --git a/app/models/bulkrax/importer.rb b/app/models/bulkrax/importer.rb index 76be42c07..6d39cf8c0 100644 --- a/app/models/bulkrax/importer.rb +++ b/app/models/bulkrax/importer.rb @@ -123,16 +123,16 @@ def last_run @last_run ||= self.importer_runs.last end + def has_failed_entries? + entries.failed.any? + end + def failed_statuses @failed_statuses ||= Bulkrax::Status.latest_by_statusable .includes(:statusable) .where('bulkrax_statuses.statusable_id IN (?) AND bulkrax_statuses.statusable_type = ? AND status_message = ?', self.entries.pluck(:id), 'Bulkrax::Entry', 'Failed') end - def failed_entries - @failed_entries ||= failed_statuses.map(&:statusable) - end - def failed_messages failed_statuses.each_with_object({}) do |e, i| i[e.error_message] ||= [] @@ -146,10 +146,6 @@ def completed_statuses .where('bulkrax_statuses.statusable_id IN (?) AND bulkrax_statuses.statusable_type = ? AND status_message = ?', self.entries.pluck(:id), 'Bulkrax::Entry', 'Complete') end - def completed_entries - @completed_entries ||= completed_statuses.map(&:statusable) - end - def seen @seen ||= {} end diff --git a/app/models/bulkrax/status.rb b/app/models/bulkrax/status.rb index fbcb5a872..ba442fd77 100644 --- a/app/models/bulkrax/status.rb +++ b/app/models/bulkrax/status.rb @@ -2,7 +2,7 @@ module Bulkrax class Status < ApplicationRecord - belongs_to :statusable, polymorphic: true + belongs_to :statusable, polymorphic: true, denormalize: { fields: %i[status_message], if: :latest? } belongs_to :runnable, polymorphic: true serialize :error_backtrace, Array @@ -21,5 +21,9 @@ def self.latest_by_statusable_subtable status_table.join(latest_status_query.as(latest_status_table.name.to_s), Arel::Nodes::InnerJoin) .on(status_table[:id].eq(latest_status_table[:latest_status_id])) end + + def latest? + self.id == self.class.where(statusable_id: self.statusable_id, statusable_type: self.statusable_type).order('id desc').pluck(:id).first + end end end diff --git a/app/models/concerns/bulkrax/status_info.rb b/app/models/concerns/bulkrax/status_info.rb index 5edc22388..02ce18838 100644 --- a/app/models/concerns/bulkrax/status_info.rb +++ b/app/models/concerns/bulkrax/status_info.rb @@ -10,6 +10,9 @@ module StatusInfo as: :statusable, class_name: "Bulkrax::Status", inverse_of: :statusable + scope :failed, -> { where(status_message: 'Failed') } + scope :complete, -> { where(status_message: 'Complete') } + scope :pending, -> { where(status_message: 'Pending') } end def current_status diff --git a/bulkrax.gemspec b/bulkrax.gemspec index db56602c9..08f34caa5 100644 --- a/bulkrax.gemspec +++ b/bulkrax.gemspec @@ -21,6 +21,7 @@ Gem::Specification.new do |s| s.add_dependency 'rails', '>= 5.1.6' s.add_dependency 'bagit', '~> 0.4' s.add_dependency 'coderay' + s.add_dependency 'denormalize_fields' s.add_dependency 'iso8601', '~> 0.9.0' s.add_dependency 'kaminari' s.add_dependency 'language_list', '~> 1.2', '>= 1.2.1' diff --git a/db/migrate/20240208005801_denormalize_status_message.rb b/db/migrate/20240208005801_denormalize_status_message.rb new file mode 100644 index 000000000..12d6ff995 --- /dev/null +++ b/db/migrate/20240208005801_denormalize_status_message.rb @@ -0,0 +1,7 @@ +class DenormalizeStatusMessage < ActiveRecord::Migration[5.2] + def change + add_column :bulkrax_entries, :status_message, :string, default: 'Pending' + add_column :bulkrax_importers, :status_message, :string, default: 'Pending' + add_column :bulkrax_exporters, :status_message, :string, default: 'Pending' + end +end diff --git a/lib/bulkrax.rb b/lib/bulkrax.rb index e88f608bf..f485a5923 100644 --- a/lib/bulkrax.rb +++ b/lib/bulkrax.rb @@ -3,6 +3,7 @@ require "bulkrax/version" require "bulkrax/engine" require 'active_support/all' +require 'denormalize_fields' # rubocop:disable Metrics/ModuleLength module Bulkrax diff --git a/lib/tasks/bulkrax_tasks.rake b/lib/tasks/bulkrax_tasks.rake index f0a741cb7..b04e0f78b 100644 --- a/lib/tasks/bulkrax_tasks.rake +++ b/lib/tasks/bulkrax_tasks.rake @@ -1,6 +1,19 @@ # frozen_string_literal: true namespace :bulkrax do + + desc 'Update all status messages from the latest status. This is to refresh the denormalized field' + task :update_status_messages => :environment do + @progress = ProgressBar.create(total: Bulkrax::Status.latest_by_statusable.count, + format:"%a %b\u{15E7}%i %c/%C %p%% %t", + progress_mark: ' ', + remainder_mark: "\u{FF65}") + Bulkrax::Status.latest_by_statusable.includes(:statusable).find_each do |status| + status.statusable.update(status_message: status.status_message) + @progress.increment + end + end + # Usage example: rails bulkrax:generate_test_csvs['5','100','GenericWork'] desc 'Generate CSVs with fake data for testing purposes' task :generate_test_csvs, [:num_of_csvs, :csv_rows, :record_type] => :environment do |_t, args| From 3a886274343a0aadcb2911de1aa793c283ce37a5 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 01:13:40 -0800 Subject: [PATCH 2/7] call the cops --- app/models/bulkrax/importer.rb | 2 +- lib/tasks/bulkrax_tasks.rake | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/app/models/bulkrax/importer.rb b/app/models/bulkrax/importer.rb index 6d39cf8c0..94c400f31 100644 --- a/app/models/bulkrax/importer.rb +++ b/app/models/bulkrax/importer.rb @@ -123,7 +123,7 @@ def last_run @last_run ||= self.importer_runs.last end - def has_failed_entries? + def failed_entries? entries.failed.any? end diff --git a/lib/tasks/bulkrax_tasks.rake b/lib/tasks/bulkrax_tasks.rake index b04e0f78b..f3da8ddac 100644 --- a/lib/tasks/bulkrax_tasks.rake +++ b/lib/tasks/bulkrax_tasks.rake @@ -1,13 +1,12 @@ # frozen_string_literal: true namespace :bulkrax do - desc 'Update all status messages from the latest status. This is to refresh the denormalized field' - task :update_status_messages => :environment do + task update_status_messages: :environment do @progress = ProgressBar.create(total: Bulkrax::Status.latest_by_statusable.count, - format:"%a %b\u{15E7}%i %c/%C %p%% %t", - progress_mark: ' ', - remainder_mark: "\u{FF65}") + format: "%a %b\u{15E7}%i %c/%C %p%% %t", + progress_mark: ' ', + remainder_mark: "\u{FF65}") Bulkrax::Status.latest_by_statusable.includes(:statusable).find_each do |status| status.statusable.update(status_message: status.status_message) @progress.increment From 7fb851ef74a8089d6bb38399947c84da67da14b9 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 00:48:25 -0800 Subject: [PATCH 3/7] Add datatable to the importer show page. search, filter, sort and paginate with ajax updates --- app/assets/javascripts/bulkrax/datatables.js | 74 +++++++++++++++++++ .../bulkrax/importers_controller.rb | 17 +++-- .../concerns/bulkrax/datatables_behavior.rb | 70 ++++++++++++++++++ app/views/bulkrax/importers/show.html.erb | 22 ++---- .../bulkrax/shared/_entries_tab.html.erb | 38 ++-------- config/routes.rb | 1 + 6 files changed, 169 insertions(+), 53 deletions(-) create mode 100644 app/assets/javascripts/bulkrax/datatables.js create mode 100644 app/controllers/concerns/bulkrax/datatables_behavior.rb diff --git a/app/assets/javascripts/bulkrax/datatables.js b/app/assets/javascripts/bulkrax/datatables.js new file mode 100644 index 000000000..17e55446c --- /dev/null +++ b/app/assets/javascripts/bulkrax/datatables.js @@ -0,0 +1,74 @@ +Blacklight.onLoad(function() { + if($('#importer-show-table').length) { + $('#importer-show-table').DataTable( { + 'processing': true, + 'serverSide': true, + "ajax": window.location.href.replace(/(\/importers\/\d+)/, "$1/entry_table.json"), + "pageLength": 30, + "lengthMenu": [[30, 100, 200], [30, 100, 200]], + "columns": [ + { "data": "identifier" }, + { "data": "id" }, + { "data": "status_message" }, + { "data": "type" }, + { "data": "updated_at" }, + { "data": "errors", "orderable": false }, + { "data": "actions", "orderable": false } + ], + "dom": '<"toolbar">frtip', + initComplete: function () { + // Add entry class filter + let select = document.createElement('select'); + select.id = 'entry-filter' + select.classList.value = 'form-control input-sm' + select.style.marginRight = '10px' + + let blankOption = new Option('Filter by Entry Class', ''); + select.add(blankOption); + // Read the options from the footer and add them to the select + $('#importer-entry-classes').text().split('|').forEach(function (col, i) { + select.add(new Option(col.trim())) + }) + document.querySelector('div#importer-show-table_filter').firstChild.prepend(select) + + // Apply listener for user change in value + select.addEventListener('change', function () { + var val = select.value; + this.api() + .search(val ? val : '', false, false) + .draw(); + }.bind(this)); + + // Add status filter + select = document.createElement('select'); + select.id = 'entry-filter' + select.classList.value = 'form-control input-sm' + select.style.marginRight = '10px' + + blankOption = new Option('Filter by Status', ''); + select.add(blankOption); + select.add(new Option('Complete')) + select.add(new Option('Pending')) + select.add(new Option('Failed')) + document.querySelector('div#importer-show-table_filter').firstChild.prepend(select) + + // Apply listener for user change in value + select.addEventListener('change', function () { + var val = select.value; + this.api() + .search(val ? val : '', false, false) + .draw(); + }.bind(this)); + + // Add refresh link + let refreshLink = document.createElement('a'); + refreshLink.onclick = function() { + this.api().ajax.reload(null, false) + }.bind(this) + refreshLink.classList.value = 'glyphicon glyphicon-refresh' + refreshLink.style.marginLeft = '10px' + document.querySelector('div#importer-show-table_filter').firstChild.append(refreshLink) + } + } ); + } +}) diff --git a/app/controllers/bulkrax/importers_controller.rb b/app/controllers/bulkrax/importers_controller.rb index 8248975cd..f7ba4fc35 100644 --- a/app/controllers/bulkrax/importers_controller.rb +++ b/app/controllers/bulkrax/importers_controller.rb @@ -6,13 +6,14 @@ class ImportersController < ::Bulkrax::ApplicationController include Hyrax::ThemedLayoutController if defined?(::Hyrax) include Bulkrax::DownloadBehavior include Bulkrax::API + include Bulkrax::DatatablesBehavior include Bulkrax::ValidationHelper protect_from_forgery unless: -> { api_request? } before_action :token_authenticate!, if: -> { api_request? }, only: [:create, :update, :delete] before_action :authenticate_user!, unless: -> { api_request? } before_action :check_permissions - before_action :set_importer, only: [:show, :edit, :update, :destroy] + before_action :set_importer, only: [:show, :entry_table, :edit, :update, :destroy] with_themed_layout 'dashboard' if defined?(::Hyrax) # GET /importers @@ -34,9 +35,15 @@ def show add_importer_breadcrumbs add_breadcrumb @importer.name end - @work_entries = @importer.entries.where(type: @importer.parser.entry_class.to_s).page(params[:work_entries_page]).per(30) - @collection_entries = @importer.entries.where(type: @importer.parser.collection_entry_class.to_s).page(params[:collections_entries_page]).per(30) - @file_set_entries = @importer.entries.where(type: @importer.parser.file_set_entry_class.to_s).page(params[:file_set_entries_page]).per(30) + @first_entry = @importer.entries.first + end + + def entry_table + @entries = @importer.entries.order(table_order).page(table_page).per(table_per_page) + @entries = @entries.where(table_search) if table_search.present? + respond_to do |format| + format.json { render json: format_entries(@entries, @importer) } + end end # GET /importers/new @@ -210,7 +217,7 @@ def files_for_import(file, cloud_files) # Use callbacks to share common setup or constraints between actions. def set_importer - @importer = Importer.find(params[:id]) + @importer = Importer.find(params[:id] || params[:importer_id]) end def importable_params diff --git a/app/controllers/concerns/bulkrax/datatables_behavior.rb b/app/controllers/concerns/bulkrax/datatables_behavior.rb new file mode 100644 index 000000000..7d4c68c23 --- /dev/null +++ b/app/controllers/concerns/bulkrax/datatables_behavior.rb @@ -0,0 +1,70 @@ +module Bulkrax + module DatatablesBehavior + extend ActiveSupport::Concern + + def table_per_page + per_page = params[:length].to_i + per_page < 1 ? 30 : per_page + end + + def order_value(column) + params['columns']&.[](column)&.[]('data') + end + + def table_order + "#{order_value(params['order']['0']['column'])} #{params['order']['0']['dir']}" if params['order']['0']['column'].present? + end + + # convert offset to page number + def table_page + params[:start].blank? ? 1 : (params[:start].to_i / params[:length].to_i) + 1 + end + + def table_search + return @table_search if @table_search + return @table_search = false if params['search']&.[]('value').blank? + + table_search_value = params['search']&.[]('value') + @table_search = ['identifier', 'id', 'status_message', 'type', 'updated_at'].map do |col| + "cast(bulkrax_entries.#{col} as varchar(255)) ILIKE '%#{table_search_value}%'" + end.join(' OR ') + end + + def format_entries(entries, item) + result = entries.map do |e| + { + identifier: view_context.link_to(e.identifier, view_context.item_entry_path(item, e)), + id: e.id, + status_message: entry_status(e), + type: e.type, + updated_at: e.updated_at, + errors: e.latest_status&.error_class&.present? ? view_context.link_to(e.latest_status.error_class, view_context.item_entry_path(item, e), title: e.latest_status.error_message) : "", + actions: util_links(e, item) + } + end + { + data: result, + recordsTotal: item.entries.size, + recordsFiltered: item.entries.size + } + end + + def util_links(e, item) + links = [] + links << view_context.link_to(view_context.raw(''), view_context.item_entry_path(item, e)) + links << "" if view_context.an_importer?(item) + links << view_context.link_to(view_context.raw(''), view_context.item_entry_path(item, e), method: :delete, data: { confirm: 'This will delete the entry and any work associated with it. Are you sure?' }) + links.join(" ") + end + + def entry_status(e) + if e.status_message == "Complete" + " #{e.status_message}" + elsif e.status_message == "Pending" + " #{e.status_message}" + else + " #{e.status_message}" + end + end + end +end diff --git a/app/views/bulkrax/importers/show.html.erb b/app/views/bulkrax/importers/show.html.erb index b95a79807..be94a2918 100644 --- a/app/views/bulkrax/importers/show.html.erb +++ b/app/views/bulkrax/importers/show.html.erb @@ -1,9 +1,10 @@

Importer: <%= @importer.name %>

- <% if @importer.parser_klass == 'Bulkrax::CsvParser' && @work_entries.map(&:failed?).any? %> + + <% if @importer.has_failed_entries? %>
- <%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary' %> - <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' %> + <%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary', data: { turbolinks: false }%> + <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' if @importer.parser.is_a?(Bulkrax::CsvParser) %>
<% end %>
@@ -75,19 +76,10 @@
- - -
- <%= render partial: 'bulkrax/shared/entries_tab', locals: { item: @importer, entries: @work_entries, pagination_param_name: :work_entries_page, pagination_anchor: 'work-entries' } %> - <%= render partial: 'bulkrax/shared/entries_tab', locals: { item: @importer, entries: @collection_entries, pagination_param_name: :collection_entries_path, pagination_anchor: 'collection-entries' } %> - <%= render partial: 'bulkrax/shared/entries_tab', locals: { item: @importer, entries: @file_set_entries, pagination_param_name: :file_set_entries_path, pagination_anchor: 'file-set-entries' } %> +
+ <%= render partial: 'bulkrax/shared/entries_tab' %>
- <% all_entries = @work_entries + @collection_entries + @file_set_entries %> - <%= render partial: 'bulkrax/importers/edit_item_buttons', locals: { item: @importer, e: all_entries.first } if all_entries.present? %> + <%= render partial: 'bulkrax/importers/edit_item_buttons', locals: { item: @importer, e: @first_entry } if @first_entry.present? %>

diff --git a/app/views/bulkrax/shared/_entries_tab.html.erb b/app/views/bulkrax/shared/_entries_tab.html.erb index d2f1da520..f87d8bd87 100644 --- a/app/views/bulkrax/shared/_entries_tab.html.erb +++ b/app/views/bulkrax/shared/_entries_tab.html.erb @@ -1,44 +1,16 @@ -

- +
+
+ + - - - <% entries.each do |e| %> - - - - <% if e.status == "Complete" %> - - <% elsif e.status == "Pending" %> - - <% else %> - - <% end %> - <% if e.last_error.present? %> - - <% else %> - - <% end %> - - - - <% end %> -
<%= t('bulkrax.table_header.labels.identifier') %> <%= t('bulkrax.table_header.labels.entry_id') %> <%= t('bulkrax.table_header.labels.status') %><%= t('bulkrax.table_header.labels.type') %><%= t('bulkrax.table_header.labels.updated_at') %> <%= t('bulkrax.table_header.labels.errors') %><%= t('bulkrax.table_header.labels.status_set_at') %> <%= t('bulkrax.table_header.labels.actions') %>
<%= link_to e.identifier, item_entry_path(item, e) %><%= e.id %> <%= e.status %> <%= e.status %> <%= e.status %><%= link_to e.last_error.dig("error_class"), item_entry_path(item, e) %><%= e.status_at %> - <%= link_to raw(''), item_entry_path(item, e) %> - <% if an_importer?(item) %> - - <% end %> - <%= link_to raw(''), item_entry_path(item, e), method: :delete, data: { confirm: 'This will delete the entry and any work associated with it. Are you sure?' } %> -
- <%= page_entries_info(entries) %>
- <%= paginate(entries, theme: 'blacklight', param_name: pagination_param_name, params: { anchor: pagination_anchor }) %> +
diff --git a/config/routes.rb b/config/routes.rb index e4a709e27..e720a4002 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -7,6 +7,7 @@ end resources :importers do put :continue + get :entry_table get :export_errors collection do post :external_sets From 72426e65f98cbbc075d82760841490ab82c5174c Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 01:02:44 -0800 Subject: [PATCH 4/7] fix filters --- app/assets/javascripts/bulkrax/datatables.js | 44 ++++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/app/assets/javascripts/bulkrax/datatables.js b/app/assets/javascripts/bulkrax/datatables.js index 17e55446c..4775e71d5 100644 --- a/app/assets/javascripts/bulkrax/datatables.js +++ b/app/assets/javascripts/bulkrax/datatables.js @@ -18,43 +18,41 @@ Blacklight.onLoad(function() { "dom": '<"toolbar">frtip', initComplete: function () { // Add entry class filter - let select = document.createElement('select'); - select.id = 'entry-filter' - select.classList.value = 'form-control input-sm' - select.style.marginRight = '10px' + let entrySelect = document.createElement('select') + entrySelect.id = 'entry-filter' + entrySelect.classList.value = 'form-control input-sm' + entrySelect.style.marginRight = '10px' - let blankOption = new Option('Filter by Entry Class', ''); - select.add(blankOption); - // Read the options from the footer and add them to the select + entrySelect.add(new Option('Filter by Entry Class', '')) + // Read the options from the footer and add them to the entrySelect $('#importer-entry-classes').text().split('|').forEach(function (col, i) { - select.add(new Option(col.trim())) + entrySelect.add(new Option(col.trim())) }) - document.querySelector('div#importer-show-table_filter').firstChild.prepend(select) + document.querySelector('div#importer-show-table_filter').firstChild.prepend(entrySelect) // Apply listener for user change in value - select.addEventListener('change', function () { - var val = select.value; + entrySelect.addEventListener('change', function () { + var val = entrySelect.value; this.api() .search(val ? val : '', false, false) .draw(); }.bind(this)); // Add status filter - select = document.createElement('select'); - select.id = 'entry-filter' - select.classList.value = 'form-control input-sm' - select.style.marginRight = '10px' + let statusSelect = document.createElement('select'); + statusSelect.id = 'status-filter' + statusSelect.classList.value = 'form-control input-sm' + statusSelect.style.marginRight = '10px' - blankOption = new Option('Filter by Status', ''); - select.add(blankOption); - select.add(new Option('Complete')) - select.add(new Option('Pending')) - select.add(new Option('Failed')) - document.querySelector('div#importer-show-table_filter').firstChild.prepend(select) + statusSelect.add(new Option('Filter by Status', '')); + statusSelect.add(new Option('Complete')) + statusSelect.add(new Option('Pending')) + statusSelect.add(new Option('Failed')) + document.querySelector('div#importer-show-table_filter').firstChild.prepend(statusSelect) // Apply listener for user change in value - select.addEventListener('change', function () { - var val = select.value; + statusSelect.addEventListener('change', function () { + var val = statusSelect.value; this.api() .search(val ? val : '', false, false) .draw(); From 9c9f3e34001ec28f61cd3864bdd736ee1fd2addf Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 01:15:49 -0800 Subject: [PATCH 5/7] call the cops --- app/controllers/concerns/bulkrax/datatables_behavior.rb | 2 ++ app/views/bulkrax/importers/show.html.erb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/controllers/concerns/bulkrax/datatables_behavior.rb b/app/controllers/concerns/bulkrax/datatables_behavior.rb index 7d4c68c23..0ba9b9098 100644 --- a/app/controllers/concerns/bulkrax/datatables_behavior.rb +++ b/app/controllers/concerns/bulkrax/datatables_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Bulkrax module DatatablesBehavior extend ActiveSupport::Concern diff --git a/app/views/bulkrax/importers/show.html.erb b/app/views/bulkrax/importers/show.html.erb index be94a2918..183a9d08d 100644 --- a/app/views/bulkrax/importers/show.html.erb +++ b/app/views/bulkrax/importers/show.html.erb @@ -1,7 +1,7 @@

Importer: <%= @importer.name %>

- <% if @importer.has_failed_entries? %> + <% if @importer.failed_entries? %>
<%= link_to 'Export Errored Entries', importer_export_errors_path(@importer.id), class: 'btn btn-primary', data: { turbolinks: false }%> <%= link_to 'Upload Corrected Entries', importer_upload_corrected_entries_path(@importer.id), class: 'btn btn-primary' if @importer.parser.is_a?(Bulkrax::CsvParser) %> From fc8c3c16b70837614e771abcfed56d7b5e1f7ec7 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 01:18:25 -0800 Subject: [PATCH 6/7] call the cops --- app/models/bulkrax/status.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/bulkrax/status.rb b/app/models/bulkrax/status.rb index ba442fd77..534f176f0 100644 --- a/app/models/bulkrax/status.rb +++ b/app/models/bulkrax/status.rb @@ -23,7 +23,7 @@ def self.latest_by_statusable_subtable end def latest? - self.id == self.class.where(statusable_id: self.statusable_id, statusable_type: self.statusable_type).order('id desc').pluck(:id).first + self.id == self.class.where(statusable_id: self.statusable_id, statusable_type: self.statusable_type).order('id desc').pick(:id) end end end From 87c69fc744f67b32b23719faa0466e42f11eca77 Mon Sep 17 00:00:00 2001 From: Rob Kaufman Date: Thu, 8 Feb 2024 01:04:23 -0800 Subject: [PATCH 7/7] Found another place we need to include the monad lib. This time so that generators work --- spec/test_app/config/application.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/test_app/config/application.rb b/spec/test_app/config/application.rb index af0ed0959..bb6896ceb 100644 --- a/spec/test_app/config/application.rb +++ b/spec/test_app/config/application.rb @@ -11,6 +11,7 @@ require "action_cable/engine" # require "rails/test_unit/railtie" require "sprockets/railtie" +require 'dry/monads' Bundler.require(*Rails.groups) require "bulkrax"