Export Rails ActiveRecords to CSV

For a recent “enterprisey” project I’m working on, we had to offer a variety of CSV exports for many of the models in our system. Ruby’s FasterCSV library is great for raw parsing and generation of CSV data, so I used that as the basis for a quick and dirty system to easily provide customizable exports.

The main features are:

  • Transform an array of exportable records into a whole CSV file. (By default, FasterCSV transforms arrays into a single CSV row.)
  • Export a whole table my calling .to_csv on the ActiveRecord subclass.
  • By default, export all of an ActiveRecord’s columns except for created_at and updated_at.
  • Allow simple customization of exportable columns by overriding the export_columns method in your ActiveRecord class.
  • Allow multiple CSV formats by conditionally branching inside the export_columns method depending on the format parameter.
  • Allow complete customization of the export by overriding the to_row method. (I haven’t actually needed this much customization yet.)

The simplest example:


Address.to_csv

Customizing the columns included in the CSV:

1
2
3
4
5
class Address < ActiveRecord::Base
  def export_columns(format = nil)
    %w[city state postal_code]
  end
end

Multiple output formats:

1
2
3
4
5
6
7
8
9
10
class Address < ActiveRecord::Base
  def export_columns(format = nil)
    case format
    when :local
      %w[street1 street2 city state postal_code]
    else
      %w[city state postal_code]
    end
  end
end

Here’s the code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
require "fastercsv"

class ActiveRecord::Base
  def self.to_csv(*args)
    find(:all).to_csv(*args)
  end
  
  def export_columns(format = nil)
    self.class.content_columns.map(&:name) - ['created_at', 'updated_at']
  end
  
  def to_row(format = nil)
    export_columns(format).map { |c| self.send(c) }
  end
end

class Array
  def to_csv(options = {})
    if all? { |e| e.respond_to?(:to_row) }
      header_row = first.export_columns(options[:format]).to_csv
      content_rows = map { |e| e.to_row(options[:format]) }.map(&:to_csv)
      ([header_row] + content_rows).join
    else
      FasterCSV.generate_line(self, options)
    end
  end
end

4 Responses to “Export Rails ActiveRecords to CSV”

  1. # John Says:

    Where in your Rails project do you put the ActiveRecord::Base and Array definitions? And do you put these in the same file, or in separate active_record.rb and array.rb files?

    TIA

  2. # Bryan Helmkamp Says:

    John—I put all of the code (for both AR::Base and Array) in a file in lib/exportable.rb

  3. # Dav Says:

    Uhm, is it just the day, or why does the code refuse to load when put in lib.

    printed the config.load_paths and lib wasn’t there.

    added {RAILS_ROOT}/lib

    still no Array.to_csv

    hmm

  4. # Abhay Says:

    This is interesting. We actually use a SQL query (SELECT … INTO OUTFILE) for our csv exports. Since the data is already there in database, we like to keep rails mostly away from it.