maxenglander
maxenglander

Reputation: 4041

in rails, unable to override content-disposition filename

I am using Rails 3.1.0.rc8 and Chromium 15.0.874.102.

I want to set the filename of a CSV download. I am following this SO solution, but find myself unable to modify the filename of the Content-Disposition header.

Here is my code:

module ActionController 
  module CSVHelper

    def render_csv options={}
      if request.env['HTTP_USER_AGENT'] =~ /msie/i
        headers['Pragma'] = "public"
        headers['Content-Type'] = "text/plain"
        headers['Cache-Control'] = "no-cache, must-revalidate, post-check=0, pre-check=0"
        headers['Expires'] = "0"
      else
        headers['Content-Type'] = "text/csv"
      end

      filename = generate_filename options.delete(:basename)
      headers['Content-Disposition'] = "attachment; filename=#{filename}"
    end

    def generate_filename basename=nil, suffix="csv"
      filename = basename || params[:action]
      filename << ".#{suffix}"
      filename
    end

  end
end    

And in my controller:

respond_to do |format|
  format.html
  format.csv do
    render_csv(:basename => "my_filename")
    Rails.logger.debug "HEADERS: #{headers.to_s}"
  end
end  

In my log:

[2011-11-28 12:25:49.611] DEBUG - HEADERS: {"Content-Type"=>"text/csv", "Content-Disposition"=>"attachment; filename=my_filename.csv"}

In Chromium network inspector tool, I see the following in my Response Headers:

Content-Type: text/plain
Content-Disposition: attachment; filename=index.csv

If I change the Content-Type to something like foo/bar, I see the change come through in my network inspector tool. No matter what I set the filename to, it remains index.csv.

Thanks, Max

Upvotes: 9

Views: 9512

Answers (4)

Nathan Crause
Nathan Crause

Reputation: 943

I personally don't use render for this sort of content - I prefer to use send_data. Here's an example:

send_data data, :type => 'text/csv', :disposition => 'attachment; filename=my_file_name.csv'

Upvotes: 3

maerics
maerics

Reputation: 156434

According to the Content-Disposition section of the appendices to the HTTP/1.1 specification the filename must be a quoted string:

   filename-parm = "filename" "=" quoted-string
   ...

An example is

   Content-Disposition: attachment; filename="fname.ext"

So you probably need to make the following change (note the quotation marks):

headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""

Upvotes: 12

Matt Connolly
Matt Connolly

Reputation: 9857

I don't see where you are actually sending / rendering the output... Is that in a .csv.erb file or something? Or using csv_builder as other answer? That could be the trick.

I came up with the same thing rendering a .xlsx output. Once I had the file on disk, I could do this:

def example
  respond_to do |format|
    format.xlsx do
      path = some_method_generating_xlsx_file
      headers['Content-Disposition'] = "attachment; filename=test.xlsx"
      render :text => File.binread(path), :content_type => XLSX_MIME_TYPE
    end
  end
end

in my controller, and it worked just fine. Perhaps the headers were being clobbered by the template rendering.

Upvotes: 1

maxenglander
maxenglander

Reputation: 4041

I found out that my team is using the csv_builder gem, which allows you to adjust the name of the downloaded file by setting @filename in the controller. Will still award correct answer to anyone who can explain why I was getting the behavior described in OP.

Upvotes: 2

Related Questions