Rails overwrite CSV - ruby-on-rails

I'm currently using this code:
CSV.open "application.csv", "a+" do |csv|
csv << [ "#{params[:first_name]}", "#{params[:last_name]}","#{params[:company]}","#{params[:email]}", "#{params[:phone]}", "#{params[:business]}", "#{params[:services]}", "#{params[:employees]}", "#{params[:turnover]}" ]
end
Which writes an extra row to the csv each time, what can I put instead of "a+" that will overwrite the entire file each time, so it always only has one row?

You should use 'w' mode. BTW, why do you write "#{params[:first_name]}" where params[:first_name] would be enough? The code should look:
CSV.open 'application.csv', 'w' do |csv|
csv << [params[:first_name], params[:last_name], params[:company], params[:email], params[:phone], params[:business], params[:services], params[:employees], params[:turnover], params[:c4l_services]]
end

Related

How to check header exist before import data in Ruby CSV?

I want to write header only 1 time in first row when import data to csv in ruby, but the header is written many time on output file.
job_datas.each do |job_data|
#company_job = job data coverted etc....
save_job_to_csv(#company_job)
end
def save_job_to_csv(job_data)
filepath = "tmp/jobs/jobs.csv"
CSV.open(filepath, "a", :headers => true) do |csv|
if csv.blank?
csv << CompanyJob.attribute_names
end
csv << job_data.attributes.values
end
end
Any one can give me solution? Thank you so much!
You are calling save_job_to_csv the method for each job_data and pushing header every time csv << CompanyJob.attribute_names
filepath = "tmp/jobs/jobs.csv"
CSV.open(filepath, "a", :headers => true) do |csv|
# push header once
csv << CompanyJob.attribute_names
# push every job record
job_datas.each do |job_data|
#company_job = job data coverted etc....
csv << #company_job.attributes.values
end
end
The above script can be created wrapped a method but if you like to write a separate method that just saves the CSV, then you need to refactor the script when you first prepare an array of values holding header and pass it to a method that just saves to CSV.
You could do something similar to this:
def save_job_to_csv(job_data)
filepath = "tmp/jobs/jobs.csv"
unless File.file?(filepath)
File.open(filepath, 'w') do |file|
file.puts(job_data.attribute_names.join(','))
end
end
CSV.open(filepath, "a", :headers => true) do |csv|
csv << job_data.attributes.values
end
end
It just checks beforehand if the file exists and if not it adds the header. If you want tabs as column separators, you just have to change the value for the join function and add the col_sep parameter to CSV.open():
file.puts(job_data.attribute_names.join("\t"))
CSV.open(filepath, "a", :headers => true, col_sep: "\t") do |csv|

Create timestamped labels on csv files (ruby code)

I am running a transaction download script through Ruby. I was wondering if it is possible to label each .csv it creates with the current date/time the script was run. Below is the end of the script.
CSV.open("transaction_report.csv", "w") do |csv|
csv << header_row
search_results.each do |transaction|
transaction_details_row = header_row.map{ |attribute| transaction.send(attribute) }
csv << transaction_details_row
end
end
Like this?
CSV.open("transaction_report-#{Time.now}.csv", "w") do |csv|
csv << header_row
search_results.each do |transaction|
transaction_details_row = header_row.map{ |attribute| transaction.send(attribute) }
csv << transaction_details_row
end
end
This just appends the time of generation to the file name. For example:
"transaction_report-#{Time.now}.csv"
# => "transaction_report-2019-10-10 16:09:07 +0100.csv"
If you want to avoid spaces in the file name, you can sub these out like so:
"transaction_report-#{Time.now.to_s.gsub(/\s/, '-')}.csv"
# => "transaction_report-2019-10-10-16:09:40-+0100.csv"
Is that what you're after? It sounds right based on the question, though happy to update if you're able to correct me :)

Rails - Export DB to CSV not reading from translation file

I've seen a number of useful suggestions here but so far haven't been able to fix my problem. I'm creating a redmine plugin (ruby on rails) and I have a button that exports the db into a CSV file. That part works just fine.
My problem is that the column names in the csv file are not being translated don't seem to be changed by a call to human_attribute_name. Can anybody point out where i've gone wrong and help me correct it?
I mostly followed this tutorial: http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast
app/models/person.rb
def self.to_csv(options={})
CSV.generate(options) do |csv|
csv << User.attribute_names.map {|c| User.human_attribute_name(c)}
# Could I instead use:
# csv << User.human_attribute_names
User.all.each do |user|
csv << user.attributes.values
end
end
end
config/locales/en.yml
en:
activerecord:
attributes:
user:
col1: "Column 1"
col2: "Column 2"
Found this solution which seems to work:
app/models/user.rb
def self.to_csv(options={})
CSV.generate(options) do |csv|
#cols = User.attribute_names #[1..-1] to remove first column from output
csv << #cols.map { |c| I18t.t c, scope: [:activerecord, :attributes, :user] }
User.all.each do |user|
csv << user.attributes.value_at(*#cols)
end
end
end

convert array of hashes to csv file

How do you convert an array of hashes to a .csv file?
I have tried
CSV.open("data.csv", "wb") do |csv|
#data.to_csv
end
but it is blank
Try this:
CSV.open("data.csv", "wb") do |csv|
#data.each do |hash|
csv << hash.values
end
end
If you want the first line of the CSV to contain the keys of the hash (a header row), simply do:
CSV.open("data.csv", "wb") do |csv|
csv << #data.first.keys # adds the attributes name on the first line
#data.each do |hash|
csv << hash.values
end
end
Please read the comment of #cgenco below: He wrote a monkey patch for the Array class.
CSV is smart enough to deal with the non-uniform hashes for you. See the code for CSV::Writer#<<
So, this works, and is a bit simpler than the above examples:
CSV.open("data.csv", "wb", {headers: #data.first.keys} ) do |csv|
#data.each do |hash|
csv << hash
end
end
If the keys are not the same in all rows, the current answers fail. This is the safest approach:
data = [{a: 1, b: 2}, {b: 3, c: 4}]
CSV.open("data.csv", "w") { |csv|
headers = data.flat_map(&:keys).uniq
csv << headers
data.each { |row|
csv << row.values_at(*headers)
}
}
All keys will be present in the CSV, even if they don't appear in the first row:
a
b
c
1
2
3
4
If the hashes aren't uniform then you will end up with data in the wrong columns. You should use values_at instead:
CSV.open("data.csv", "wb") do |csv|
keys = #data.first.keys
csv << keys
#data.each do |hash|
csv << hash.values_at(*keys)
end
end
None of the other answers worked for me for one reason or another, so I'll throw in my contribution as well. Here's what worked for me for my array of hashes with ruby 2.7:
headers = data.map(&:keys).flatten.uniq
CSV.open("data.csv", "wb", {headers: headers} ) do |csv|
csv << headers
data.each do |hash|
csv << hash
end
end

How to solve when parsing CSV file return empty values?

I am using ruby 1.9.2 and Rails 3.0.7. I have written ruby back-end script that will create one CSV file on every 15 min interval using cron job.
Back-end ruby script:
CSV.open("count.csv", 'wb',:col_sep=>',') do |csv|
# header row
csv << ['id', 'count']
models = Model.all
models.each do |obj|
csv << [ obj.id, obj.get_count]
end
end
From above script CSV file(count.csv) created successfully. In Rails app,
CSV.foreach("count.csv", :quote_char => '"', :col_sep =>',', :row_sep =>:auto, :headers => true) do |row|
count = row["count"].to_i if row["id"].to_i == #id
end
I need to parse count value from that CSV file. but problem is when the time of cron execution, I unable to get count value from that CSV file return zero for all record and after execution finish I can get value of count. But I need count value always whether the cron execution stop or start, Can any one help me to resolve or any suggestion ? Thanks in advance.
models = Model.all
models.each do |obj|
csv_string << [ obj.id, obj.get_count]
end
CSV.open("count.csv", 'wb',:col_sep=>',') do |csv|
# header row
csv << ['id', 'count']
csv << csv_string
end

Resources