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.