CSV file formatting options during creation - ruby-on-rails

I have the following code which contains data for the csv file.Now i want the data to be displayed aligned left for all the columns.
CSV.open("projects.csv",'w') do |row|
if user.god?
row << ["Project Name","Manager","Total Resources","Hours Required"]
each_project_detail.each do |project_detail|
row << [project_detail["project_name"], project_detail["manager_name"].join("\n"), project_detail["total_resources"], project_detail["estimated_hours"].round, project_detail["development_hours"].round, project_detail["extra_hours"].round]
end
else
row << ["Project Name","Hours Required","Hours Spent", "Extra Hours"]
each_project_detail.each do |project_detail|
row << [project_detail["project_name"], project_detail["estimated_hours"].round, project_detail["development_hours"].round, project_detail["extra_hours"].round]
end
end
end

CSV files cannot have formatting. There's no concept of alignment in columns. It's just comma separated values!

Related

New line in csv cell (rails)

I'd like multiple pieces of data on different lines within the same CSV cell like this:
"String" 2-15-2021 05:26pm
"String ..."
"String..."
I have tried the following and ended up with \n in the cell and not an actual new line, like this "2-15-2021 05:26pm \nHi, it's ...".
["\n", time, text.body].join("\n")
[time, text.body, "\n"].join("\n")
[time, text.body].join("\n")
The input data is an array of hashes. The output of a row is a hash with keys and values, one of the values is a list of strings (or this can be a list of lists of string, I am playing with what I can get to work). The list of strings is where I am trying to add line breaks.
I am using this to create the csv:
CSV.open("data.csv", "wb") do |csv|
csv << list.first.keys
list.each do |hash|
csv << hash.values
end
end
I ended up needing a list of strings that I could then join and add new lines onto.
values = []
values.push("#{time}, #{text.body}")
# And then in the hash for the csv, setting the value for that column like this:
{ message: values.join("\n\n")}

How to write data to excel file

I have a config table as below:
S.NO TableName SourceColumns
1 A a,b,c,d
2 B p,q,r,s,t,u
3 C m,n,o,p,q
4 D x,y,z
Here, result object consists of SourceColumns of each record from the table.
For instance, here it gets the 1 record values. Then I am writing those values to CSV(excel) file. This works.
CSV.open('C:\Actual\Test.csv', 'w') do |csv|
result.each do |eachrow|
csv << ["#{eachrow['a']}","#{eachrow['b']}","#{eachrow['c']}","#{eachrow['d']}"]
end
end
As, I have hardcoded my values in the above query, I am constructing the string per my SourceColumns and passing to query as below:
myformattedstring="#{eachrow['a']}","#{eachrow['b']}","#{eachrow['c']}","#{eachrow['d']}"
CSV.open('C:\Actual\Test.csv', 'w') do |csv|
result.each do |eachrow|
csv << [myformattedstring]
end
end
Now, the data is being treated as string. How, can i pass my string to the CSV so that I can write the actual values
If you want to insert only 1 column in your csv containing myformattedstring, you need to put the double quotes only at the beginning and the end of your string, and interpolate all the #{} inside those quotes, as opposed to repeating the quotes

Ruby - Output file in CSV comes in one column

I am trying to print my values in CSV file like following where data is array of hashes.
UPDATES:
CSV.open(fn, "wb") do |csv|
#first rows are always headers and the headers value is generated from the array of hashes
data.each do |name, values|
csv << [name, values.join(",")]
end
and values has data like : true,false,false,false and name is an array with data like: light.
But for some reason my columns are only 2 instead of 5. The values column is concatenated in one column.
How can I achieve multiple columns using above code ?
I think this should work:
CSV.open(fn, "wb") do |csv|
data.each do |name, values|
csv << [name, *values]
end
end
http://ruby-doc.org/core-2.0.0/doc/syntax/calling_methods_rdoc.html#label-Array+to+Arguments+Conversion

Can Rails sort a CSV file?

I'm exporting a CSV from many different sources which makes it very hard to sort before putting it into the CSV.
csv = CSV.generate col_sep: '#' do |csv|
... adding a few columns here
end
Now, it would be awesome if I was able to sort this CSV by the 2nd column. Is that in any way possible?
If you're trying to sort before writing, it depends on your data structure, in which i'll need to see your code a bit more. For reading a csv, you can convert it to hash and sort by header name even:
rows = []
CSV.foreach('mycsvfile.csv', headers: true) do |row|
rows << row.to_h
end
rows.sort_by{ |row| row['last_name'] }
Edit to use sort_by, thanks to max williams.
Here is how you would sort by column number:
rows = []
CSV.foreach('mycsvfile.csv', headers: true) do |row|
# collect each row as an array of values only
rows << row.to_h.values
end
# sort in place by the 2nd column
rows.sort_by! { |row| row[1] }
rows.each do |row|
# do stuff with your now sorted rows
end

How to insert a column in the existing CSV file

I have already CSV file, the content like
a1 a2 a3
1 2 3
4 5 6
5 8 2
Now, What I want, when I read any row i want to add a flag in the csv file like
a1 a2 a3 flag
1 2 3 1
4 5 6 1
5 8 2
the above flag 1 that means this record is inserted in the table.
so How can I add flag in the csv file?
Thanks In Advance
I came up with two ways to append a column(s) to an existing CSV file.
Method 1 late merges the new column by reading the file into an array of hashes, then appending the columns to the end of each row. This method can exhibit anomalies if run multiple times.
require 'csv'
filename = 'test.csv'
# Load the original CSV file
rows = CSV.read(filename, headers: true).collect do |row|
row.to_hash
end
# Original CSV column headers
column_names = rows.first.keys
# Array of the new column headers
additional_column_names = ['flag']
# Append new column name(s)
column_names += additional_column_names
s = CSV.generate do |csv|
csv << column_names
rows.each do |row|
# Original CSV values
values = row.values
# Array of the new column(s) of data to be appended to row
additional_values_for_row = ['1']
values += additional_values_for_row
csv << values
end
end
# Overwrite csv file
File.open(filename, 'w') { |file| file.write(s) }
Method 2 early merges the new column(s) into the row hash. The nicety of this method is it is more compact and avoids duplicate column names if run more than once. This method can also be used to change any existing values in the CSV.
require 'csv'
filename = 'test.csv'
# Load the original CSV file
rows = CSV.read(filename, headers: true).collect do |row|
hash = row.to_hash
# Merge additional data as a hash.
hash.merge('flag' => '0')
# BONUS: Change any existing data here too!
hash.merge('a1' => hash['a1'].to_i + 1 )
end
# Extract column names from first row of data
column_names = rows.first.keys
txt = CSV.generate do |csv|
csv << column_names
rows.each do |row|
# Extract values for row of data
csv << row.values
end
end
# Overwrite csv file
File.open(filename, 'w') { |file| file.write(txt) }
You need to write new CSV file with additional column, and then replace original file with new one.
Not sure if you can append a new column in the same file, but you can append a new row into your csv:
CSV.open('your_csv.csv', 'w') do |csv|
customers.array.each do |row|
csv << row
end
end
Hope this helps.

Resources