Peter Marklund

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'],
                ... more values here ...]

    filename =[^0-9a-z]/, "_") + ".csv"
      :type => 'text/csv; charset=utf-8; header=present',
      :filename => filename)

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)

    rows = []
    reader.each do |row|
      rows << row
    assert_equal rows.size, lists(:peterlist).size
    item = lists(:peterlist).items.first
    item_row = { |row| row[1] == }.first
    assert_equal item_row[0], 'Contact'
    assert_equal item_row[1],
    ... assertions for the other attribute values here ...

To see what CSV export from a controller looks like with the Ruby CSV library - check out this blog post.