Rails3 and Standard Library CSV
Recently I had learned how to write a csv file in my rails app using the fasterCSV gem. In Rails3, CSV is now part of the standard library, so things are a little different. I also did a few trickier things this time around, so I’m updating my notes.
In Gemfile, add:
require 'csv'
As before, create config/download_csv.yml
development: all: /Users/me/Desktop/all.csv current: /Users/me/Desktop/current.csv previous: /Users/me/Desktop/previous.csv production: all: /tmp/all.csv current: /tmp/current.csv previous: /tmp/previous.csv
In the model, add a method to make the csv file.
def self.download_charges(project_id, timeframe) csv_settings = YAML.load_file("#{Rails.root.to_s}/config/ download_csv.yml")[Rails.env] filename = csv_settings[timeframe] if (timeframe == 'current') @entries = Entry.billable.current_month.where(:project_id => project_id).newest_first end if (timeframe == 'previous') @entries = Entry.billable.previous_month.where(:project_id => project_id).newest_first end if (timeframe == 'all') @entries = Entry.billable.where(:project_id => project_id).newest_first end CSV.open("#{filename}",'w') do |csv| csv << ["Report Generated On #{Time.now.to_s(:fulldate)}"] csv << ["Account", "#{@entries.first.project.account}", "#{@entries.first.project.subaccount}"] csv << ["#{@entries.first.project.name}"] csv << ["Total Charges", "#{@entries.sum(:cost)}"] csv << [""] csv << ['Date','Staff Member', 'Hours', 'Charge', 'Note'] @entries.each do |entry| csv << ["#{entry.start_date.to_s(:fulldate)}", "#{entry.user.fullname}","#{entry.hours}", "#{entry.cost}", "#{entry.note}"] end end end
In the controller, make a method to call.
def download_charges csv_settings = YAML.load_file("#{Rails.root.to_s}/config/ download_csv.yml")[Rails.env] filename = csv_settings["#{params[:timeframe]}"] Entry.download_charges(params[:project_id], params[:timeframe]) send_file "#{filename}", :type => 'text/csv' end
and add it to the filter_resource access line.
filter_resource_access :additional_collection => [[:download_charges, :index], :index]
To my routes file, add:
resources :entries do collection do get 'download_charges', :as => :download_charges end end
Lastly, in my view, add the required links. Here they’re a little trickier because I want the same method to work for different time frames.
<% unless params[:project_id].nil? %><% end %> <%= link_to 'Download All Charges', :controller => :entries, :action => :download_charges, :project_id => @entries.first.project_id, timeframe => 'all' %> <%= link_to 'Download Current Month Charges', :controller => :entries, :action => :download_charges, :project_id => @entries.first.project_id, :timeframe => 'current'%> <%= link_to 'Download Previous Month Charges', :controller => :entries, :action => :download_charges, :project_id => @entries.first.project_id, :timeframe => 'previous'%>