From eb23dd9662aaadf647e4300e3d5e1bff6372594a Mon Sep 17 00:00:00 2001 From: Igor Fedoronchuk Date: Mon, 15 Jun 2026 12:18:20 +0200 Subject: [PATCH 1/2] fix: raise a clear error on blank CSV column headers (#197) A CSV with an empty header cell (e.g. a leading comma) produced a nil header, and prepare_headers crashed with `undefined method 'underscore' for nil`. Merely coercing the header to a string only moves the failure to import time (`Missing column for value <> at index 0`), since an unnamed column maps to no attribute. Detect blank headers up front and raise an ActiveAdminImport::Exception naming the offending column, so the user gets an actionable flash instead of a NoMethodError. --- lib/active_admin_import/importer.rb | 9 ++++++++- spec/fixtures/files/authors_empty_header.csv | 3 +++ spec/import_spec.rb | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/files/authors_empty_header.csv diff --git a/lib/active_admin_import/importer.rb b/lib/active_admin_import/importer.rb index d37c9ab..4272476 100644 --- a/lib/active_admin_import/importer.rb +++ b/lib/active_admin_import/importer.rb @@ -129,7 +129,14 @@ def process_file end def prepare_headers - headers = self.headers.present? ? self.headers.map(&:to_s) : yield + headers = self.headers.present? ? self.headers : yield + blank_positions = headers.each_index.select { |i| headers[i].to_s.strip.empty? } + unless blank_positions.empty? + raise ActiveAdminImport::Exception, + "blank column header at column #{blank_positions.map { |i| i + 1 }.join(', ')}" + end + + headers = headers.map(&:to_s) @headers = Hash[headers.zip(headers.map { |el| el.underscore.gsub(/\s+/, '_') })].with_indifferent_access @headers.merge!(options[:headers_rewrites].symbolize_keys.slice(*@headers.symbolize_keys.keys)) @headers diff --git a/spec/fixtures/files/authors_empty_header.csv b/spec/fixtures/files/authors_empty_header.csv new file mode 100644 index 0000000..a6cfa99 --- /dev/null +++ b/spec/fixtures/files/authors_empty_header.csv @@ -0,0 +1,3 @@ +,Name,Last name,Birthday +x,John,Doe,1986-05-01 +y,Jane,Roe,1988-11-16 diff --git a/spec/import_spec.rb b/spec/import_spec.rb index 595acfb..fca15d1 100644 --- a/spec/import_spec.rb +++ b/spec/import_spec.rb @@ -190,6 +190,22 @@ def upload_file!(name, ext = 'csv') end end + # Issue #197: a CSV with an empty header cell used to crash with + # `undefined method 'underscore' for nil`. + context 'with a blank column header' do + before do + add_author_resource + visit '/admin/authors/import' + upload_file!(:authors_empty_header) + end + + it 'reports a clear error and imports nothing' do + expect(page).to have_content 'blank column header at column 1' + expect(page).to have_no_content 'undefined method' + expect(Author.count).to eq(0) + end + end + context 'authors already exist' do before do Author.create!(id: 1, name: 'Jane', last_name: 'Roe') From d55bdd79755a660aa46d4875b39a171feb70c946 Mon Sep 17 00:00:00 2001 From: Igor Fedoronchuk Date: Mon, 15 Jun 2026 12:28:28 +0200 Subject: [PATCH 2/2] test: cover blank CSV header in the middle and at the end (#197) Generalize the blank-header spec into a shared example and exercise a blank column at the beginning (col 1), the middle (col 2) and the end (col 4), asserting the reported column position for each. --- .../files/authors_blank_header_end.csv | 3 ++ .../files/authors_blank_header_middle.csv | 3 ++ spec/import_spec.rb | 32 +++++++++++++------ 3 files changed, 29 insertions(+), 9 deletions(-) create mode 100644 spec/fixtures/files/authors_blank_header_end.csv create mode 100644 spec/fixtures/files/authors_blank_header_middle.csv diff --git a/spec/fixtures/files/authors_blank_header_end.csv b/spec/fixtures/files/authors_blank_header_end.csv new file mode 100644 index 0000000..327f466 --- /dev/null +++ b/spec/fixtures/files/authors_blank_header_end.csv @@ -0,0 +1,3 @@ +Name,Last name,Birthday, +John,Doe,1986-05-01,x +Jane,Roe,1988-11-16,y diff --git a/spec/fixtures/files/authors_blank_header_middle.csv b/spec/fixtures/files/authors_blank_header_middle.csv new file mode 100644 index 0000000..22bfe51 --- /dev/null +++ b/spec/fixtures/files/authors_blank_header_middle.csv @@ -0,0 +1,3 @@ +Name,,Last name,Birthday +John,x,Doe,1986-05-01 +Jane,y,Roe,1988-11-16 diff --git a/spec/import_spec.rb b/spec/import_spec.rb index fca15d1..f904cf8 100644 --- a/spec/import_spec.rb +++ b/spec/import_spec.rb @@ -191,18 +191,32 @@ def upload_file!(name, ext = 'csv') end # Issue #197: a CSV with an empty header cell used to crash with - # `undefined method 'underscore' for nil`. + # `undefined method 'underscore' for nil`, wherever the blank sits. context 'with a blank column header' do - before do - add_author_resource - visit '/admin/authors/import' - upload_file!(:authors_empty_header) + shared_examples 'a rejected blank header' do |fixture, column| + before do + add_author_resource + visit '/admin/authors/import' + upload_file!(fixture) + end + + it 'reports a clear error and imports nothing' do + expect(page).to have_content "blank column header at column #{column}" + expect(page).to have_no_content 'undefined method' + expect(Author.count).to eq(0) + end + end + + context 'at the beginning' do + it_behaves_like 'a rejected blank header', :authors_empty_header, 1 + end + + context 'in the middle' do + it_behaves_like 'a rejected blank header', :authors_blank_header_middle, 2 end - it 'reports a clear error and imports nothing' do - expect(page).to have_content 'blank column header at column 1' - expect(page).to have_no_content 'undefined method' - expect(Author.count).to eq(0) + context 'at the end' do + it_behaves_like 'a rejected blank header', :authors_blank_header_end, 4 end end