13

I am attempting to generate a CSV file. Everything is fine except for blank fields, I'm not quite sure have "" instead of actual quotes. I've provided the code I'm using to generate the file and some output.

<% headers = ["Username", "Name", "E-mail", "Phone Number"] %>
<%= CSV.generate_line headers %>

<% @users_before_paginate.each do |user| %>
  <% row = [ "#{user.username}".html_safe ] %>
  <% row << "#{user.profile.first_name} #{user.profile.last_name}".html_safe unless user.profile.blank? %>
  <% row << "#{user.email}".html_safe unless user.profile.nil? %>
  <% row << "#{user.profile.phone}".html_safe unless user.profile.nil? %>
  <%= CSV.generate_line row %>
<% end %>

Output

Username,Name,E-mail,Phone Number

  admin,LocalShopper ,shoplocally1@gmail.com,&quot;&quot;
  Brian,Oliveri Design ,brian@oliveridesign.com,727-537-9617
  LocalShopperJenn,Jennifer M Gentile ,localshopperjenn@hotmail.com,&quot;&quot;
Adam Leonard
  • 133
  • 1
  • 5

2 Answers2

32

Instead of calling html_safe on each part of the array and then making a new (non-html-safe) string from it, try calling it at the end, after the string is returned from generate_line:

<%= CSV.generate_line(row).html_safe %>

UPDATE: For security, you need to be sure that this template is not being sent to the browser as HTML, but a raw text/csv file. If the row content contains any actual HTML tags like <script>, these would not get escaped, because you've declared the output as "safe".

If this content needs to be output within an HTML page, then you'd better consider correct escaping instead of bypassing it like this.

Consider if you really need a html.erb template for generating CSV.

Andrew Vit
  • 18,961
  • 6
  • 77
  • 84
1

Here's a template I've used that works well enough:

<%=
  response.content_type = 'application/octet-stream'

  FasterCSV.generate do |csv|
    csv << @report[:columns]
    @report[:rows].each do |row|
      csv << row
    end
  end
%>

You can do this entirely within the controller if you like and render it as type :text instead.

It also helps if you wrangle the content into order, in this case a simple @report hash, inside the controller than to do all the heavy lifting in the view.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • Thanks this is a useful template, not exactly what I was looking for, but it will be good for future reference. – Adam Leonard Nov 29 '10 at 19:36
  • You'd put that into a file called `export.csv.erb` for example to ensure it is not HTML escaped. – tadman Dec 01 '10 at 22:39
  • 1
    @tadman That is actually not correct. You must explicitly mark CSV output as html safe, even if it's in a .csv.erb file. Further, your answer seems to be advocating putting view code into the controller which doesn't make any sense. – latortuga Jan 10 '12 at 16:18