CSV Exports using csv_builder

Having gotten some sample reports working using RaphaelJS (see previous post), I needed to provide a CSV export as well. I’ve done this before, but I had a feeling that there might be an easier way now, and sure enough I found the csv_builder plugin. Built on top of the old reliable FasterCSV gem, the plugin provides CSV exporting using templates, so you can simply add a respond_to in your controller for the “csv” format, and you’re done.

Of course, it’s never quite that easy. The issues I had were mainly around working out a nice way to set up the routes and getting things to respond correctly. I’m still not entirely happy with the results yet, but they’re not bad so I’ll share the info here.

First, the routes. I ended up needing two routes, unfortunately, one that includes the :format designation and one that doesn’t. See this blog post for more.

  map.connect 'reports/:action.:format', :controller => 'reports'
  map.connect 'reports/:action', :controller => 'reports'

This allows the use of links like “/reports/monthly” to get the HTML output (with the RaphaelJS graphs) and “/reports/monthly.csv” to get the CSV export. In the controller, then:

  def monthly
    # gather up the data
    respond_to do |format|
      format.html {}
      format.csv do
        @output_encoding = 'UTF-16'
        @filename = "Monthly_Report"
      end
    end
  end

That takes care of handling both the HTML and the CSV formats, which are automatically farmed out to the appropriate templates: /app/views/reports/monthly.html.erb for the HTML, and /app/views/reports/monthly.csv.csvbuilder for the CSV. It also sets a couple of parameters for csv_builder, including the encoding (UTF-16 seems to make the file slightly more Excel-friendly) and the filename which will be delivered to the browser as the default for downloading. Other parameters are available — see the plugin’s README for more.

In the CSV template, it’s a simple matter of building the rows of the file:

csv << [ 'Month', 'Totals' ]
@monthly.each_with_index do |month_value, i|
    csv << [ @month_names[i], month_value ]
end

This is using the structure assembled by the controller, which fills @month_names with the names of the 12 months, and @monthly with the numbers for each month. The first line creates the header row with the field names, and then the code simply iterates through the @monthly array. The resulting CSV file has the header row, and 12 rows following, one for each month.

This is obviously a very simple CSV, which was the idea so I could demonstrate that the CSV export is working. On my report page, I ended up creating simple links to get the three forms of report that I'm providing: bar chart, pie chart, and CSV export:

<%= link_to('Bar Chart', :controller => "reports", :action => "monthly", :chart => 'bar') %> |
<%= link_to('Pie Chart', :controller => "reports", :action => "monthly", :chart => 'pie') %> |
<%= link_to('Export CSV', :controller => "reports", :action => "monthly", :format => 'csv') %>

As you can see, I can use params[:chart] to determine which chart type to display, and :format is automatically used to delegate to the csv_builder template.

I'm pretty pleased with how simple this is to work with, once the basics were figured out. The template is easy to work with, and once I set up the data in the controller's action method, everything just happens like it should.

I want to give a quick link to this blog post, which had some helpful hints on this as well.

About these ads
2 comments
  1. Michael said:

    It seems that the .format behaviour has change somewhere in Rails 2.3.x.

    I have dropped the duplicate routes and use :format => nil and the dot is gone as well.

    Have a nice day,
    Michael.

  2. Ah, that’s good news. I’ll check that and see, thanks very much for your note!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: