How can i read csv file datas from csv files in ruby on rails
Here goes a working example of reading CSV, instantiating Person
object and printing.
# following the directory tree:
# ./
# ./tasks/main.rb
# ./csv/department.csv
#
# csv file example
#
# name,surname,department
# John,Doe,IT
# Bill,Doe,IT
#
# running this code:
# ruby tasks/main.rb
require 'csv'
class Person
def initialize(name, surname, department)
@name = name
@surname = surname
@department = department
end
def print_full_name
puts "#{@name} #{@surname}"
end
end
### main
filepath = "#{__dir__}/../csv/department.csv"
CSV.foreach(filepath, headers: true) do |row|
person = Person.new(
row["name"],
row["surname"],
row["department"]
)
person.print_full_name
end
Your code in the question wasn't written in ruby way. I recommend you to read this ruby styleguide to follow some practices on our community
Ruby view csv data
There are several ways you can read a set number of records, and you need to pick which to use based on the anticipated size of your data source.
Starting with a CSV file:
A1,A2,A3
B1,B2,B3
C1,C2,C3
D1,D2,D3
E1,E2,E3
F1,F2,F3
The simplest ways to read a fixed number of records would be one of these:
require 'csv'
array = CSV.read('test.csv')[0, 2]
Which returns an array of two sub-arrays:
[
[0] [
[0] "A1",
[1] "A2",
[2] "A3"
],
[1] [
[0] "B1",
[1] "B2",
[2] "B3"
]
]
An alternate is:
File.new('test.csv').readlines[0, 2].map{ |l| CSV.parse(l).flatten }
Which returns the same result, an array of two sub-arrays:
[
[0] [
[0] "A1",
[1] "A2",
[2] "A3"
],
[1] [
[0] "B1",
[1] "B2",
[2] "B3"
]
]
Both of these are fine for small input files, but will have problems if you are reading a few lines from a big input file. They will force Ruby to read the entire file into memory and create an intermediate array before slicing off the number of records you want. Where I work it's nothing for us to get gigabyte file sizes, so grabbing a small section of those files would make Ruby and the system do an inordinate amount of work building the intermediate array then throwing it away.
You are better off to only read the minimum number of records needed. Sometimes lines need to be skipped before reading; This demonstrates that idea, along with handling EOFError
if the input file's EOF is encountered unexpectedly:
File.open('test.csv') do |fi|
array = []
begin
5.times { fi.readline }
2.times.each{ array += CSV.parse(fi.readline) }
rescue EOFError
end
end
Replace 5
with the number of records to skip, and 2
with the number to read. For that example I deliberately read off the end of the file to show how to skip lines, read some and then handle the EOF situation cleanly.
The data looks like:
[
[0] [
[0] "F1",
[1] "F2",
[2] "F3"
]
]
Because I'm using File.open
with a block, the file is closed automatically after the block exists, avoiding leaving an open filehandle hanging around.
The HAML output section of your question isn't well defined at all, but this is one way to output the data:
array = []
File.open('test.csv') do |fi|
begin
0.times { fi.readline }
2.times.each{ array += CSV.parse(fi.readline) }
rescue EOFError
end
end
require 'haml'
engine = Haml::Engine.new(<<EOT)
%html
%body
%table
- array.each do |r|
%tr
- r.each do |c|
%td= c
EOT
puts engine.render(Object.new, :array => array)
Which results in this output of a simple HTML table:
<html>
<body>
<table>
<tr>
<td>A1</td>
<td>A2</td>
<td>A3</td>
</tr>
<tr>
<td>B1</td>
<td>B2</td>
<td>B3</td>
</tr>
</table>
</body>
</html>
EDIT:
and my test file: dl.dropbox.com/u/59666091/qnt_small.csv i want to see this 7 columns in browser (via haml view)
Using this as my test data:
a1,a2,a3,a4,a5,a6,a7
b1,b2,b3,b4,b5,b6,b7
c1,c2,c3,c4,c5,c6,c7
d1,d2,d3,d4,d5,d6,d7
e1,e2,e3,e4,e5,e6,e7
and this code:
require 'csv'
array = []
File.open('test.csv') do |fi|
begin
0.times { fi.readline }
2.times.each{ array += CSV.parse(fi.readline) }
rescue EOFError
end
end
require 'haml'
engine = Haml::Engine.new(<<EOT)
%html
%body
%table
- array.each do |r|
%tr
- r.each do |c|
%td= c
EOT
puts engine.render(Object.new, :array => array)
I get this output:
<html>
<body>
<table>
<tr>
<td>a1</td>
<td>a2</td>
<td>a3</td>
<td>a4</td>
<td>a5</td>
<td>a6</td>
<td>a7</td>
</tr>
<tr>
<td>b1</td>
<td>b2</td>
<td>b3</td>
<td>b4</td>
<td>b5</td>
<td>b6</td>
<td>b7</td>
</tr>
</table>
</body>
</html>
I made a minor change to move array
outside the File.open
block, nothing else is different.
Fetch the data from the CSV files in ruby and Order the Data in DESC?
You need column names in the CSV if you want to use the row["COL"]
csv syntax.
Additionally you need to use +=
not =
to add them up. Right now you're just overwriting the value every time.
Name,Sales
Randy, 200
Robin, 502
Randy, 200
Raj, 502
Randy, 500
Robin, 102
Mano, 220
Raj, 502
Randy, 285
Robin, 385
Randy, 295
Raj, 596
require 'csv'
cust = Hash.new
CSV.foreach(("./data.csv"), headers: true, col_sep: ",") do |row|
# if key isn't in hash start it at 0
unless cust.keys.include?(row["Name"])
cust[row["Name"]] = 0
end
# add the sales (.to_i converts to integer)
cust[row["Name"]] += row["Sales"].to_i
end
puts "Name Sales Rank"
# Sort by the value not the key. Make it negative so it's descending
# not ascending.
# each_with_index is just a nice way to count them
cust.sort_by{|k,v| -v}.each_with_index do |(name, sales), i|
puts "#{name} #{sales} #{i+1}"
end
Produces:
Raj 1600 1
Randy 1480 2
Robin 989 3
Mano 220 4
How to read the filename of a csv file in ruby
You can list all the CSV files in the dropbox folder and check if they match the pattern. Then extract the information you need and create the test:
Dir.glob('yourdropboxfolder/*.csv').each do |filename|
name = File.basename(filename, '.csv')
if (match = /(\d+)_(.*).csv/.match(name))
student_id = match[1]
test_name = match[2]
create_test_for(student_id, test_name, File.read(filename))
end
end
Not sure if you need to extract the values from the filename or if this information is also in the file.
Related Topics
What Does "File.Sync = True" Do
Can You Have Multiple Versions of a Gem in a Gemfile
Quote All Fields in CSV Output
Split Float into Integer and Decimals in Ruby
How to Pass Multi Value Query Params in Swagger
Accessing a Ruby Hash with a Variable as the Key
Gmaps4Rails:Setting Map Width and Height
How to Run Rails App in a Completely Isolated Instances of Chrome
Pg_Dump: [Archiver (Db)] Query Failed: Error: Permission Denied for Relation Abouts
No Such File or Directory @ Rb_Sysopen for External Url/Rails 6.11/Ruby 3
Uri::Invalidurierror: Bad Uri(Is Not Uri) Testing Rails Controllers
Shading Mask Algorithm for Radiation Calculations
How to Create an Association Between Two Rails Models
Config Undefined in Environment Specific Configuration Files
Devise Rendering Default Views from Gem Instead of Generated Ones