CSV Methods for ActiveRecord Models

John Harlan, 12 months ago

The following content comes from our github.com account. You can view the gem here. Here is a gem we built for adding default CSV behavior to ActiveRecord models using Ruby on Rails.

Overview

Extending default CSV behavior to Active Record models making it easier to offer CSV downloads. The default behavior should iterate over all, belongs_to, has_one and has_many  associations and add methods for names and counts.

Installation

First, include in your Gemfile:

You can get the list of columns for a class by calling.MyKlass.csv_columns This includes columns for singular and plural associations, as well as any additional custom columns you can configure (see below). You can then call to_csv on an instance of an ActiveRecord model and it will export the objects attributes to CSV in order of the columns for that class.

Default Associations Output Behavior

Singular (belongs_to and has_one)

For belongs_to and has_one associations, the to_csv instance method and csv_columns class method will check if the target model has a name attribute and will output if it exists. Otherwise, it will default to outputting the _id attribute of the target model.

Multiple (has_many)

For has_many associations, the default behavior is to add a count attribute. This can be overridden by adding a method in the class of the model you want to override. Example:

Additional configuration

You can also add additional columns to be outputted in the default CSV export by adding the optional_csv_attributesmethod to the target model:

Some columns should be filtered from the output and you can create model level filters with the filter_names method:

Angular.js, ResourceController and fully-functional downloads

Here's the ResourceController setup with an amended index method to catch the .csv format request:

Working with Angular

You can't download files from a server using XHR requests, which is what the ajax request from Angular's $http service makes. There's tons of quirky workarounds on the web, but it's easiest just to do <a target='_sef' href='/some/path?{{ransackParams(q)}}'> and then let the Rails server and browser handle the file downloading with Angular out of the way. We want to offer the flexibility to download any model using Ransack and only deliver the rows that meet the Ransack criteria. We have historically avoiding sending a get request with Ransack to the API from Angular because of the pain in Url encoding a complex JS object. What we overlooked was the built-in functionality of the jQuery library. So its as easy as this:

Like What you see? We should talk!