в рельсах невозможно переопределить имя файла содержимого

Я использую Rails 3.1.0.rc8 и Chromium 15.0.874.102.

Я хочу установить имя файла загрузки CSV. Я следую этому SO-решению, но не могу изменить filename заголовка Content-Disposition.

Вот мой код:

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    

И в моем контроллере:

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

В моем журнале:

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

В инструменте сетевого инспектора Chromium я вижу следующее в своих заголовках ответов:

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

Если я изменю Content-Type на что-то вроде foo/bar, я увижу, что изменение произошло в моем инструменте сетевого инспектора. Независимо от того, что я установил для filename, оно остается index.csv.

Спасибо, Макс


person maxenglander    schedule 28.11.2011    source источник
comment
у вас правильно настроено представление?   -  person baol    schedule 28.11.2011
comment
представление отображается так, как ожидалось, если вы это имеете в виду; содержимое загруженного файла выглядит так, как я хочу   -  person maxenglander    schedule 28.11.2011


Ответы (4)


Согласно разделу Content-Disposition приложений к спецификации HTTP/1.1 имя файла должно быть строкой в ​​кавычках:

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

Примером является

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

Поэтому вам, вероятно, нужно внести следующее изменение (обратите внимание на кавычки):

headers['Content-Disposition'] = "attachment; filename=\"#{filename}\""
person maerics    schedule 26.11.2012
comment
Обратите внимание, что если само имя файла может содержать кавычки, вам нужно их экранировать - filename.gsub(/"/, '\\"') - person gmcnaughton; 03.07.2015

Я обнаружил, что моя команда использует гем csv_builder, который позволяет настроить имя загружаемого файла. установив @filename в контроллере. По-прежнему будет давать правильный ответ любому, кто может объяснить, почему я получаю поведение, описанное в OP.

person maxenglander    schedule 28.11.2011

Лично я не использую render для такого рода контента — я предпочитаю использовать send_data. Вот пример:

send_data data, :type => 'text/csv', :disposition => 'attachment; filename=my_file_name.csv'
person Nathan Crause    schedule 20.02.2018

Я не вижу, где вы на самом деле отправляете/отображаете вывод... Это файл .csv.erb или что-то в этом роде? Или использовать csv_builder в качестве другого ответа? Это может быть трюк.

Я придумал то же самое, отображая вывод .xlsx. Когда у меня был файл на диске, я мог сделать это:

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

в моем контроллере, и он работал просто отлично. Возможно, заголовки были затерты рендерингом шаблона.

person Matt Connolly    schedule 24.11.2012