Rails 3.x export to CSV and TSV
published Wednesday, January 25, 2012
Register the TSV Mime Type
in `config/initializers/mime_types.rb` register the TSV mime type
Mime::Type.register "text/tab-separated-values", :tsv
Add to_csv and to_tsv to Arrays so as CSV and TSV renderers
In `lib/csv_and_tsv_renderers.rb`
# encoding: utf-8
#
require 'csv' # adds a .to_csv method to Array instances
class Array
BOM = "\xEF\xBB\xBF" #Byte Order Mark UTF-8
alias old_to_csv to_csv #keep reference to original to_csv method
def to_csv(options = Hash.new)
options = options.merge(:force_quotes => true)
# override only if first element actually has as_csv method
return old_to_csv(options) unless self.first.respond_to? :as_csv
# use keys from first row as header columns
out = first.as_csv.keys.collect{|k| k.to_s.titleize }.to_csv(options)
# collect all entries as CSV, ensure that no line break is present within values
self.each { |r| out << r.as_csv.values.to_csv(options).gsub(/\r?\n/, ' ').strip! + "\n" }
# Force encoding to UTF-16LE and add Byte Order Mark for Excel compatibility
(BOM + out).force_encoding("UTF-8")
end
def to_tsv(options = Hash.new)
to_csv(options.merge(:col_sep => "\t"))
end
end
ActionController::Renderers.add :csv do |csv, options|
csv = csv.respond_to?(:to_csv) ? csv.to_csv() : csv
self.content_type ||= Mime::CSV
self.response_body = csv
end
ActionController::Renderers.add :tsv do |tsv, options|
tsv = tsv.respond_to?(:to_tsv) ? tsv.to_tsv() : tsv
self.content_type ||= Mime::TSV
self.response_body = tsv
end
Load the lib
In `config/initializers/load_libs.rb`
require 'csv_and_tsv_renderers'
In your models
Cherry pick the attributes you like to be exported
def as_csv(options = {})
csv = {
attribute_1: attribute_1,
...
}
end
In your controllers
respond_to do |format|
...
format.csv { send_data @objects.to_csv(), :filename => "nice_filename.csv" }
format.tsv { send_data @objects.to_tsv(), :filename => "nice_filename.tsv" }
end
References
http://blog.plataformatec.com.br/2009/09/exporting-data-to-csv-and-excel-in-your-rails-app/
https://github.com/ilmotta/to-csv/issues/3
http://blog.grayproductions.net/articles/ruby_19s_string
http://stackoverflow.com/questions/539294/how-do-i-determine-file-encoding-in-osx
Update 2012-01-28
Use UTF-8 everywhere instead of the initial UTF-8 BOM then forcing to UTF-16LE. Seems to work fine under Windows' Office 2010.
If you could confirm that it works properly under an other version, opens fine and shows diacritics characters, please leave a comment bellow.