Greyhounddad
Greyhounddad

Reputation: 115

Rails adding a row to a csv that only has headers and no data removes the headers

I am reading a CSV file from a CDN and adding data to it then writing it back to a CDN for this reason I can't use append file.

I am also reordering the file which is why I have to turn it back into a CSV::Table

This code is a slimed down version of what I have but the problem is still replicated.

class SomeForm::Form
  class << self

    def add
      data = CSV.parse(open(csv_file_url).read, headers: true)
      data << ['david', 'smith'] # this will be dynamic
      # data = data.sort_by { |row| [row['Firstname'], row['Lastname']] }
      write_csv_file(CSV::Table.new(data).to_csv)
    end


    def csv_file_url
      #somecode to get the file_url
    end

    def write_csv_file(data)
      #somecode to write the file to the cdn
    end
  end
end

CSV file

Firstname,Lastname

So if I run SomeForm::Form.add with the csv file as above it outputs (removing the headers)

,
David,smith

However if the CSV file has at least one record in eg

Firstname,Lastname
Steve,Cougan

and run the code it adds the new record as expected

Firstname,Lastname
Steve,Cougan
david,smith

I would like to get this to work with csv with data in and csv with just the headers in.

As a aside this is for a rails3 project, though the above is replicatable in rails 5 as well

Thanks in advance

Upvotes: 0

Views: 1007

Answers (2)

Greyhounddad
Greyhounddad

Reputation: 115

I have done some research following on from Chrisians answer.

And think this may be the problem https://github.com/ruby/csv/issues/75

Upvotes: 0

Christian Bruckmayer
Christian Bruckmayer

Reputation: 2187

I simplified the script but I can't really reproduce your issue.

data = CSV.parse("Firstname,Lastname", headers: true)
data << ['david', 'smith'] # this will be dynamic
data = data.sort_by { |row| [row['Firstname'], row['Lastname']] }
puts CSV::Table.new(data).to_csv

# Firstname,Lastname
# david,smith

However, if you still experience an issue I believe it might be the sorting. The CSV::Table class is an enumerable but only iterates over the CSV rows without the headers (except in col mode) so that means your sorting might just return an array of arrays without the header. When you now initialize the new CSV::Table it will by default use the first row as the headers. Please note that you can access and set the headers as well like this.

data = CSV.parse("Firstname,Lastname", headers: true)
headers = data.headers

data << ['david', 'smith'] # this will be dynamic
data = data.sort_by { |row| [row['Firstname'], row['Lastname']] }

puts CSV::Table.new(data, headers: headers).to_csv

Here are the links to the implementation:

Upvotes: 1

Related Questions