gary1410
gary1410

Reputation: 307

Missing or stray quote in line 1 (CSV::MalformedCSVError)

I'm having issues importing this CSV file in ruby/rails

The error message I'm getting is this:

Missing or stray quote in line 1 (CSV::MalformedCSVError)

But I'm not sure what's happening because my CSV looks perfectly fine. Here's sample data below:

"lesley_grades","lesley_id","last","first","active","site","cohort","section","sections_title","faculty","completed_term_cred","term","sec_start_date","sec_end_date","grade","stc_cred","active_program","most_recent_program","intent_filed","stc_term_gpa","sta_cum_gpa","start_term","prog_status","last_change_date"
,1234456,John,Doe,TRUE,"Baltimore, MD",0002012,14/FA_ERLIT_6999_U15AA,Directed Independent Study,"Jane Hicks , Jill Saunders",2,14/FA,9/3/14,12/17/14,B-,2,EME.2270.TCBAL.01,EME.2270.TCBAL.01, ,3.3,3.148,12/SU,A,9/2/14
,1234455,John,Doe,TRUE,"Baltimore, MD",0002012,14/FA_ERSPD_6999_U15AG,Directed Independent Study,"Jane Hicks , Jill Saunders",3,14/FA,9/3/14,12/17/14,A-,3,EME.2270.TCBAL.01,EME.2270.TCBAL.01, ,3.3,3.148,12/SU,A,9/2/14

To give context, effectively the csv looks like this, with the lesley_grades as the first column. The over CSV script file will look for the first column and check that active an Active Record object, then it stores it the db with that exact same model name, assuming all migrations are pre-set.

lesley_grades   lesley_id   last   first    active  
                 1234556    Doe    John     TRUE    
                 1123445    Doe    John     TRUE

Here's part of the code that's causing me issues

def import!(csv)
 csv_reader = CSV.parse(csv)
 ActiveRecord::Base.transaction do
  csv_reader.each do |row|
    set_record_class_and_columns(row) if header_row?(row)

    if columns_mapping_defined? && record_class_defined? && record_row?(row)
      import_row(row)
    end
  end
  if imports_failed?
    puts 'Aborting importing and rolling back...'
    show_errors
    raise ActiveRecord::Rollback
  end
end

end

It can't get passed this line csv_reader = CSV.parse(csv)

before I put the quotes in the headers I was getting this error

Unquoted fields do not allow \r or \n (line 1). (CSV::MalformedCSVError)

UPDATE

The CSV gets started from the command line like this:

rails runner scripts/import_csv.rb < lesley_grades.csv

which then gets initialized here

CSVImporter.new.import!($stdin)

But as @smathy suggests I changed the method to CSV.parse(csv.gsub /\r/, '')

but now the def import! method to take in a gsub block produces this error

in `import!': undefined method `gsub' for #<IO:<STDIN>> (NoMethodError)

Not sure how to make CSV an object?

Any suggestions or refactoring to make this work? Thanks all

Upvotes: 7

Views: 15472

Answers (3)

Mosab Sasi
Mosab Sasi

Reputation: 1130

This error can also be caused by double quotes that do not come at the beginning of a field and are not escaped with two double quotes.

The error would occur in third field in the following example:

"Issue", "posted by Gary", "He said "I'm having issues importing" ","12345"

The double quotes in "I'm having issues" will be caught by the regular-expression (/[^"]"[^"]/) found in stray_quote, a variable in the csv.rb file used to raise the MalformedCSVError error on line 1863.

To get around this, you'll need to escape the double quotes with another double quote like so:

"He said ""I'm having issues importing"" "

Hope this helps.

Upvotes: 3

Diego d&#39;Ursel
Diego d&#39;Ursel

Reputation: 91

You may also encounter this issue if the CSV column separation character is not correctly set.

By default, Ruby assumes ,. This is true for most open source software, like OpenOffice. Microsoft Excel, in the contrary, uses ; when exporting to CSV.

Therefore, use the col_sep option like so:

CSV.parse(csv, col_sep: ';')

Upvotes: 2

smathy
smathy

Reputation: 27961

Your CSV data came from Windows and has CRLF (ie. "\r\n") line endings instead of "\n", you'll need to strip out the "\r"s before trying to parse it:

CSV.parse(csv.gsub /\r/, '')

Update

After additional info from OP:

CSV.parse(csv.read.gsub /\r/, '')

Upvotes: 16

Related Questions