Home > Back-end >  How to add an array of hashes into a csv file?
How to add an array of hashes into a csv file?

Time:12-15

I found this code and it fits me nicely, i transformed it into this one:

def write_in_file(file_name, hash)
    column_names = hash.first.keys
    s=CSV.generate do |csv|
        csv << column_names
        hash.each do |x|
            csv << x.values
        end
    end
File.write("#{file_name}.csv", s)
end

This is how my array of hashes looks:

[
  {:Name => "John", :Age => 26, :Country => America},
  {:Name => "Ivan", :Age => 34, :Country => Russia},
  {:Name => "Pablo", :Age => 20, :Country => Columbia}
]

But the problem is that every time I call this method - it rewrites whole file. How to change it, if i want to save this headers and add new information every iteration?

CodePudding user response:

You can append to an existing file by using mode: 'a': (see open modes)

File.write("#{file_name}.csv", s, mode: 'a')

To write the headers only on the first run, you could check whether the file exists. In addition, you should use a fixed header and fetch the hash values in that specific order, e.g.:

CSV.generate do |csv|
  csv << %w[Name Age Country] unless File.exist?("#{file_name}.csv")

  hash.each do |x|
    csv << x.values_at(:Name, :Age, :Country)
  end
end

File.write("#{file_name}.csv", s, mode: 'a')

There's also CSV.open which creates the file for you:

CSV.open("#{file_name}.csv", 'a') do |csv|
  csv << %w[Name Age Country] if csv.stat.zero?

  hash.each do |x|
    csv << x.values_at(:Name, :Age, :Country)
  end
end

Since the file will always exist when the block gets executed, the header check needs to be changed: csv.stat returns the file's File::Stat and zero? determines whether the file is empty.

  • Related