7

I have the below background job that writes to a csv file and emails it out. I am using the Tempfile class so the file is removed after I email it to the user. Currently, when I look at the csv file I am producing the results look like the following:

["Client Application"    "Final Price"   "Tax"   "Credit"    "Base Price"    "Billed At"     "Order Guid"    "Method of Payment Guid"    "Method of Payment Type"]
["web"   nil     nil     nil     nil     nil     nil     "k32k313k1j3"   "credit card"]

Please ignore the data, but the issue is, it is being written directly to the file in the ruby format and not removing the "" and [] characters.

Please see the code below:

class ReportJob
@queue = :report_job

 def self.perform(client_app_id, current_user_id)
  user = User.find(current_user_id)
  client_application = Application.find(client_app_id)
  transactions = client_application.transactions
  file = Tempfile.open(["#{Rails.root}/tmp/", ".csv"]) do |csv|
    begin
     csv << ["Application", "Price", "Tax", "Credit", "Base Price", "Billed At", "Order ID", "Payment ID", "Payment Type"]
     transactions.each do |transaction|
      csv << "\n"
      csv << [application.name, transaction.price, transaction.tax, transaction.credit, transaction.base_price, transaction.billed_at, transaction.order_id, transaction.payment_id, transaction.payment_type]
    end
   ensure
    ReportMailer.send_rev_report(user.email, csv).deliver
    csv.close(unlink_now=false)
    end
  end
end

end

Would this be an issue with using the tempfile class instead of the csv class? or is there something I could do to change the way it is being written to the file?

Adding the code for reading the csv file in the mailer. I am currently getting a TypeError that says "can't convert CSV into String".

class ReportMailer < ActionMailer::Base
 default :from => "test@gmail.com"

  def send_rev_report(email, file)
     attachments['report.csv'] = File.read("#{::Rails.root.join('tmp', file)}")
      mail(:to => email, :subject => "Attached is your report")
    end
  end
end
halfer
  • 19,824
  • 17
  • 99
  • 186
BC00
  • 1,589
  • 3
  • 29
  • 47

4 Answers4

15

The issue is that you're not actually writing csv data to the file. You're sending arrays to the filehandle. I believe you need something like:

Tempfile.open(....) do |fh|
    csv = CSV.new(fh, ...)
    <rest of your code>
end

to properly setup the CSV output filtering.

Dave S.
  • 6,349
  • 31
  • 33
  • Thank You! Would you know the proper way to read from an <#CSV io_type:Tempfile object? I am currently getting a TypeError: can't convert CSV into String when trying to read from it... – BC00 Jan 28 '13 at 16:25
  • Can you show me the code for that piece? If you're reading from the same handle as you just wrote to - don't forget to rewind the handle (or seek() to the beginning). Otherwise you'll be trying to read from EOF. – Dave S. Jan 28 '13 at 17:34
  • Why bother writing the CSV file here if you're just going to read it back in? You may as well just point the CSV writer at a stringio object and then the mailer can just assign that directly. – Dave S. Jan 28 '13 at 21:41
6

Here's how I did it.

patient_payments = PatientPayment.all

Tempfile.new(['patient_payments', '.csv']).tap do |file|
  CSV.open(file, 'wb') do |csv|
    csv << patient_payments.first.class.attribute_names

    patient_payments.each do |patient_payment|
      csv << patient_payment.attributes.values
    end
  end
end
Jason Swett
  • 43,526
  • 67
  • 220
  • 351
3

I prefer to do

tempfile = Tempfile.new(....)
csv = CSV.new(tempfile, ...) do |row|
  <rest of your code>
end
poramo
  • 546
  • 5
  • 7
1

try this:

Tempfile.open(["#{Rails.root}/tmp/", ".csv"]) do |outfile|
  CSV::Writer.generate(outfile) do |csv|
    csv << ["Application", "Price", "Tax", "Credit", "Base Price", "Billed At", "Order ID", "Payment ID", "Payment Type"]
    #...
  end
end
Miguel Prz
  • 13,718
  • 29
  • 42