![]() |
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.