в рельсах, как вернуть записи в виде csv файла - PullRequest
55 голосов
/ 18 сентября 2008

У меня есть простая таблица базы данных под названием «Записи»:

class CreateEntries < ActiveRecord::Migration
  def self.up
    create_table :entries do |t|
      t.string :firstName
      t.string :lastName
      #etc.
      t.timestamps
    end
  end

  def self.down
    drop_table :entries
  end
end

Как мне написать обработчик, который будет возвращать содержимое таблицы Entries в виде файла CSV (в идеале, таким образом, чтобы он автоматически открывался в Excel)?

class EntriesController < ApplicationController

  def getcsv
    @entries = Entry.find( :all )

    # ??? NOW WHAT ????

  end

end

Ответы [ 10 ]

88 голосов
/ 18 сентября 2008

FasterCSV - это определенно правильный путь, но если вы хотите обслуживать его непосредственно из приложения Rails, вам также понадобится настроить некоторые заголовки ответа.

Я держу метод для установки имени файла и необходимых заголовков:

def render_csv(filename = nil)
  filename ||= params[:action]
  filename += '.csv'

  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['Content-Disposition'] = "attachment; filename=\"#{filename}\"" 
    headers['Expires'] = "0" 
  else
    headers["Content-Type"] ||= 'text/csv'
    headers["Content-Disposition"] = "attachment; filename=\"#{filename}\"" 
  end

  render :layout => false
end

Использование этого позволяет легко иметь что-то подобное в моем контроллере:

respond_to do |wants|
  wants.csv do
    render_csv("users-#{Time.now.strftime("%Y%m%d")}")
  end
end

И иметь вид, который выглядит следующим образом: (generate_csv от FasterCSV)

UserID,Email,Password,ActivationURL,Messages
<%= generate_csv do |csv|
  @users.each do |user|
    csv << [ user[:id], user[:email], user[:password], user[:url], user[:message] ]
  end
end %>
25 голосов
/ 18 сентября 2008

Я принял (и проголосовал!) @ Ответ Брайана, чтобы сначала указать мне на FasterCSV. Затем, когда я погуглил, чтобы найти драгоценный камень, я также нашел довольно полный пример на этой вики-странице . Собрав их вместе, я остановился на следующем коде.

Кстати, команда для установки гема: sudo gem установить быстрееcsv (все строчные)

require 'fastercsv'

class EntriesController < ApplicationController

  def getcsv
      entries = Entry.find(:all)
      csv_string = FasterCSV.generate do |csv| 
            csv << ["first","last"]
            entries.each do |e|
              csv << [e.firstName,e.lastName]
            end
          end
          send_data csv_string, :type => "text/plain", 
           :filename=>"entries.csv",
           :disposition => 'attachment'

  end


end
24 голосов
/ 21 октября 2008

Другой способ сделать это без использования FasterCSV:

Требуется библиотека csv для ruby ​​в файле инициализатора, например config / initializers / dependencies.rb

require "csv"

В качестве некоторого фона следующий код основан на Расширенной форме поиска Райана Бэйта , которая создает поисковый ресурс. В моем случае метод show ресурса поиска вернет результаты ранее сохраненного поиска. Он также отвечает на csv и использует шаблон представления для форматирования желаемого результата.

  def show
    @advertiser_search = AdvertiserSearch.find(params[:id])
    @advertisers = @advertiser_search.search(params[:page])
    respond_to do |format|
      format.html # show.html.erb
      format.csv  # show.csv.erb
    end
  end

Файл show.csv.erb выглядит следующим образом:

<%- headers = ["Id", "Name", "Account Number", "Publisher", "Product Name", "Status"] -%>
<%= CSV.generate_line headers %>
<%- @advertiser_search.advertisers.each do |advertiser| -%>
<%- advertiser.subscriptions.each do |subscription| -%>
<%- row = [ advertiser.id,
            advertiser.name,
            advertiser.external_id,
            advertiser.publisher.name,
            publisher_product_name(subscription),
            subscription.state ] -%>
<%=   CSV.generate_line row %>
<%- end -%>
<%- end -%>

В html-версии страницы отчета у меня есть ссылка для экспорта отчета, который просматривает пользователь. Ниже приводится ссылка link_to, которая возвращает версию отчета в формате csv:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
23 голосов
/ 18 сентября 2008

Существует плагин под названием FasterCSV, который прекрасно справляется с этим.

7 голосов
/ 18 сентября 2008

Посмотрите на камень FasterCSV .

Если все, что вам нужно, - это поддержка Excel, вы можете также обратиться к генерации xls напрямую. (См. Электронную таблицу :: Excel)

gem install fastercsv
gem install spreadsheet-excel

Я считаю эти параметры хорошими для открытия файла CSV в Windows Excel:

FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... }

Что касается части ActiveRecord, то примерно так будет:

CSV_FIELDS = %w[ title created_at etc ]
FasterCSV.generate do |csv|
  Entry.all.map { |r| CSV_FIELDS.map { |m| r.send m }  }.each { |row| csv << row }
end
2 голосов
/ 22 июня 2012

Следующий подход хорошо работал для моего случая и заставляет браузер открывать соответствующее приложение для типа CSV после загрузки.

def index
  respond_to do |format|
    format.csv { return index_csv }
  end
end

def index_csv
  send_data(
    method_that_returns_csv_data(...),
    :type => 'text/csv',
    :filename => 'export.csv',
    :disposition => 'attachment'
  )
end
2 голосов
/ 18 сентября 2008

Вам необходимо установить заголовок Content-Type в вашем ответе, а затем отправить данные. Content_Type: application / vnd.ms-excel должно сработать.

Возможно, вы также захотите установить заголовок Content-Disposition так, чтобы он выглядел как документ Excel, и браузер выбирал разумное имя файла по умолчанию; это что-то вроде Content-Disposition: attachment; имя файла = "# {} suggested_name .xls"

Я предлагаю использовать более быстрый CSV Ruby Gem для создания вашего CSV, но есть также встроенный CSV. Пример кода quickcsv (из документации к гему) выглядит следующим образом:

csv_string = FasterCSV.generate do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
# ...
end
1 голос
/ 17 июля 2012

попробуйте хороший гем для генерации CSV из Rails https://github.com/crafterm/comma

0 голосов
/ 19 июля 2013

Если вы просто хотите получить базу данных csv самостоятельно из консоли, вы можете сделать это в несколько строк

tags = [Model.column_names]
rows = tags + Model.all.map(&:attributes).map(&:to_a).map { |m| m.inject([]) { |data, pair| data << pair.last } }
File.open("ss.csv", "w") {|f| f.write(rows.inject([]) { |csv, row|  csv << CSV.generate_line(row) }.join(""))}
0 голосов
/ 25 июля 2012

Посмотрите на камень CSV Shaper.

https://github.com/paulspringett/csv_shaper

Он имеет хороший DSL и отлично работает с моделями Rails. Он также обрабатывает заголовки ответа и позволяет настраивать имя файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...