Как мне создать временный файл и записать в него, а затем разрешить пользователям загружать его? - PullRequest
3 голосов
/ 29 декабря 2011

Я работаю над своим первым приложением, и мне нужна помощь, чтобы позволить моим пользователям загружать текстовый файл с определенными переменными, которые отображаются на странице.

Возьмите, например, список покупок.Допустим, вы разрешаете своим пользователям создавать список покупок продуктов, а затем отображать список покупок с элементами на странице списка покупок,
например, localhost: 3000 / list / my-list


Взгляните на приведенный ниже пример кода (который, вероятно, неверен):

File.open('shopping_list.txt', 'w') do |file|
  file.puts 'Item 1: #{product_1.name}'
  file.puts 'Item 2: #{product_2.name}'
  file.puts 'Item 3: #{product_3.name}'
end



, который затем создает текстовый файл со следующим содержанием:

Item 1: Eggs
Item 2: Butter
Item 3: Bread


Пользователи должны иметь возможность загрузить этот файл (я не хочу, чтобы этот файл хранился на сервере) по ссылке для скачивания.

Понятия не имеюкак этого добиться, но я надеюсь, что вы, ребята, сможете мне помочь.: D


TL; DR

  • создавать текстовые файлы, заполненные данными модели (возможно, создать метод для достижения этой цели?)
  • текстовые файлы не должны храниться на сервере, но должны создаваться по мере того, как пользователи нажимают кнопку загрузки (не уверен, что это путь по рельсам, но, возможно, кто-то может показать мне лучший способ)

Ответы [ 5 ]

7 голосов
/ 06 января 2012

Я предполагаю, что есть ресурс для List с атрибутом name в качестве имени списка и списка has_many Элемент, имеющий атрибут description

Сначала создайтепуть загрузки измените ваши маршруты config/routes.rb

resources :lists do
  member {get "download"}
end

Теперь, если вы запустите rake routes в консоли, вы увидите маршрут, подобный

/lists/:id/download

Что еще у вас должно бытьпомощники download_list_url & download_list_path для использования в вашем представлении, такие как

<ul>
<% @lists.each do |list| %>
  <li> <%= list.name %> - <%= link_to 'Download List', download_list_path(list) %> </li>
<% end %>
</ul>

В вашем lists_controller добавьте действие, и, поскольку вы на самом деле не хотите сохранять файл на диске сервера, просто выполните потоковую передачуданные в виде строки

def download
  list = List.find(params[:id])
  send_data list.as_file,
    :filename => "#{list.name}.txt",
    :type => "text/plain"
end

Наконец, вы видите, что я использовал метод as_file, который вы должны добавить в модель (я предпочитаю не делать этого в контроллерах, толстых моделях, тощих контроллерах).Так в List модели

def as_file
  output = [self.name]
  self.items.each {|item| output << item.description }
  output.join("\n")
end
3 голосов
/ 29 декабря 2011

Вы говорите, что не хотите хранить файл на сервере, а «скачиваете» его по запросу;Похоже, вы просто хотите сгенерировать и доставить текстовый документ в ответ на ссылку для скачивания.Есть несколько подходов, но вы должны быть уверены, что установили mime-тип, чтобы браузер воспринимал его как текстовый файл вместо html-документа.

product_info = [
    "Item 1: #{product_1.name}",
    "Item 2: #{product_2.name}",
    "Item 3: #{product_3.name}",
  ].join("\n")

render :text => product_info # implies :content_type => Mime::Type["text/plain"]

Кстати, ваш пример с open / put вышене будет выводить то, что вы думаете, поскольку строки в одинарных кавычках не интерполируются.

3 голосов
/ 02 января 2012

Итак, вы хотите:

  • create text files populated with model data (perhaps create a method to achieve this?)
  • text files should not be stored on the server, but created as users click the download button (not sure if this is the rails way but perhaps someone could show me a better way)

У вас есть правильная идея, вот что нужно сделать:

  1. Создайте метод в вашей модели для генерации содержимого текстового файла.Допустим, этот метод называется list_data

  2. Похоже, у вас есть существующее действие контроллера под названием my_list.Следовательно, мы можем вызвать наш новый метод в контроллере следующим образом:

.

def my_list
  # pre-existing code
  respond_to do |format|
    format.html   # show html page as before
    format.text do
      send_data @list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
    end
  end
end

Для ссылки на загрузку просто используйте link_to :action => my_list, :format => 'text'

См. http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data для полной документации по send_data

Предостережение и объяснения: Используя вышеописанный метод, в действительности нет явного создания файлов, Rails транслирует его для вас.Следовательно, этот метод не подходит для очень больших файлов или когда генерация содержимого файла займет некоторое время.Используйте отложенный метод, чтобы сгенерировать файл и сохранить его - содержимое файла где-нибудь, если это так - но мы можем использовать send_data, как только он будет сгенерирован

1 голос
/ 29 декабря 2011

Вы можете попробовать комбинацию TempFile и send_file. В вашем контроллере действие ..

file = Tempfile.new('foo')
file.write("hello world")
file.close

send_file file.path
0 голосов
/ 04 января 2012

В Rails 2.3 вы можете использовать Template Streaming .Работая с Redmine, я помню что-то подобное, вы должны адаптироваться к вашему делу.Справка: Потоковая передача и загрузка файлов

require "prawn" 
class ClientsController < ApplicationController

  # Generate a PDF document with information on the client and return it.
  # The user will get the PDF as a file download.
  def download_pdf
    client = Client.find(params[:id])
    send_data(generate_pdf, :filename => "#{client.name}.pdf", :type => "application/pdf")
  end

private

  def generate_pdf(client)
    Prawn::Document.new do
      text client.name, :align => :center
      text "Address: #{client.address}" 
      text "Email: #{client.email}" 
    end.render
  end

end

Используя Thong Kuah, вы просто должны изменить параметр "content_type":

def my_list
  # pre-existing code
  respond_to do |format|
    format.html   # show html page as before
    format.text do
      send_data @list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...