|
Peter Marklund's Home |
Rails Recipe: CSV Export
A common requirement from customers is the ability to export tabular data to a CSV file that can be imported into Excel. Ruby on Rails uses the standard Ruby CSV library to import test fixtures that are in CSV format. However, there is a runner up CSV library called FasterCSV which as the name suggests is faster and also has a much cleaner API. I was hesitant to use FasterCSV in production since it is still in Beta but after finding the discussion about including FasterCSV in the Ruby standard library I decided to give it a try.
The first step was to download the latest FasterCSV tgz file and extract into RAILS_HOME/vendor/fastercsv. I then added the following line to config/environment.rb:
require 'fastercsv/lib/faster_csv'
The action that exports the CSV data looks roughly like the following:
def csv
@list = @group.lists.find(params[:id])
csv_string = FasterCSV.generate do |csv|
csv << ["Type", "Name", ... more attribute names here ... ]
@list.records.each do |record|
csv << [record['type'],
record['name'],
... more values here ...]
end
end
filename = @list.name.downcase.gsub(/[^0-9a-z]/, "_") + ".csv"
send_data(csv_string,
:type => 'text/csv; charset=utf-8; header=present',
:filename => filename)
end
In the corresponding controller test I check that the CSV response can be parsed with the other CSV parser, that there is a header row with expected attributes, that the number of data rows is correct, and finally that one of the rows has the correct values:
def test_csv
get_success :csv, :id => lists(:peterlist).id
reader = CSV::Reader.create(@response.body)
header = reader.shift
['Type', 'Name', ... more attributes here ...].each do |attribute|
assert header.include?(attribute)
end
rows = []
reader.each do |row|
rows << row
end
assert_equal rows.size, lists(:peterlist).size
item = lists(:peterlist).items.first
item_row = rows.select { |row| row[1] == item.contact.name }.first
assert_equal item_row[0], 'Contact'
assert_equal item_row[1], item.name
... assertions for the other attribute values here ...
end
To see what CSV export from a controller looks like with the Ruby CSV library - check out this blog post.