Class: Bulkrax::ValidationErrorCsvBuilder

Inherits:
Object
  • Object
show all
Defined in:
app/services/bulkrax/validation_error_csv_builder.rb

Overview

Builds a CSV string containing all validation errors from a guided import.

Output columns, in order:

1. row        — 1-based row number from the source CSV (blank for file-level rows)
2. errors     — all error messages for that row, joined with " | "
3. categories — distinct validator categories for that row's errors (e.g.
                "missing_required_value | invalid_parent_reference"),
                joined with " | "; blank for file-level rows
4..N. the original CSV headers, carrying the raw cell values

File-level errors (missing required columns, unrecognized headers, empty columns, missing files) appear first as summary rows with a blank ‘row` and `categories` cell. Row-level errors follow, one output row per data row.

Usage:

csv = Bulkrax::ValidationErrorCsvBuilder.build(
  headers:     result[:headers],
  csv_data:    result[:raw_csv_data],
  row_errors:  result[:rowErrors],
  file_errors: {
    missing_required: result[:missingRequired],
    unrecognized:     result[:unrecognized],
    empty_columns:    result[:emptyColumns],
    missing_files:    result[:missingFiles]
  }
)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(headers:, csv_data:, row_errors:, file_errors:) ⇒ ValidationErrorCsvBuilder

Returns a new instance of ValidationErrorCsvBuilder.



58
59
60
61
62
63
# File 'app/services/bulkrax/validation_error_csv_builder.rb', line 58

def initialize(headers:, csv_data:, row_errors:, file_errors:)
  @headers    = headers
  @csv_data   = csv_data
  @row_errors = row_errors
  @file_errors = file_errors
end

Class Method Details

.build(headers:, csv_data:, row_errors:, file_errors: {}) ⇒ String

Returns CSV content.

Parameters:

  • headers (Array<String>)

    original CSV headers in order

  • csv_data (Array<Hash>)

    one entry per data row; each hash has :raw_row (String-keyed hash of column=>value)

  • row_errors (Array<Hash>)

    each hash describes a single row-level validation result with the following keys:

    • :row [Integer] 1-based source row number (header is row 1)

    • :message [String] human-readable error/warning message

    • :category [String, nil] validator category slug used to populate the ‘categories` output column (e.g. ’missing_required_value’, ‘invalid_parent_reference’); omitted/nil categories are dropped

    • :severity, :column, :value, :suggestion, :source_identifier — not emitted by this builder but commonly present on the same hash

  • file_errors (Hash) (defaults to: {})

    file-level issues:

    • :missing_required [Array<Hash>] each hash has :model and :field

    • :unrecognized [Hash] column_name => suggestion_or_nil

    • :empty_columns [Array<Integer>] 1-based column positions with no header

    • :missing_files [Array<String>] filenames referenced but not found

Returns:

  • (String)

    CSV content



54
55
56
# File 'app/services/bulkrax/validation_error_csv_builder.rb', line 54

def self.build(headers:, csv_data:, row_errors:, file_errors: {})
  new(headers: headers, csv_data: csv_data, row_errors: row_errors, file_errors: file_errors).build
end

Instance Method Details

#buildObject



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'app/services/bulkrax/validation_error_csv_builder.rb', line 65

def build
  errors_by_row = group_errors_by_row
  blank_data    = Array.new(@headers.length)

  CSV.generate(force_quotes: false) do |csv|
    csv << ['row', 'errors', 'categories'] + @headers

    file_level_error_rows.each do |message|
      csv << [nil, message, nil] + blank_data
    end

    @csv_data.each_with_index do |record, index|
      row_number = index + 2 # header is row 1; first data row is row 2
      row_errors = errors_by_row[row_number]
      error_messages   = row_errors&.map { |e| e[:message] }&.join(' | ')
      error_categories = row_errors&.map { |e| e[:category] }&.compact&.uniq&.join(' | ')
      raw_row = record[:raw_row] || {}
      csv << [row_number, error_messages, error_categories] + @headers.map { |h| raw_row[h] }
    end
  end
end