w rails, jak zwracać rekordy jako plik csv

Mam prostą tabelę bazy danych o nazwie "Entries":

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

Jak napisać program obsługi, który zwróci zawartość tabeli Entries jako plik CSV (najlepiej w taki sposób, aby automatycznie otwierała się w Excelu)?

class EntriesController < ApplicationController

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

    # ??? NOW WHAT ????

  end

end
Author: Eric, 2008-09-18

10 answers

Istnieje plugin o nazwie FasterCSV, który radzi sobie z tym wspaniale.

 23
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 17:07:43

FasterCSV to zdecydowanie najlepszy sposób, ale jeśli chcesz go obsługiwać bezpośrednio z aplikacji Rails, powinieneś też skonfigurować kilka nagłówków odpowiedzi.

Trzymam metodę aby ustawić nazwę pliku i potrzebne nagłówki:

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

Używanie tego ułatwia posiadanie czegoś takiego w moim kontrolerze:

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

I mieć widok, który wygląda tak: (generate_csv jest z 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 %>
 89
Author: Clinton Dreisbach,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 17:21:41

Zaakceptowałem (i zagłosowałem!@ Brian ' s answer, za pierwsze wskazanie mi FasterCSV. Następnie, gdy googlowałem, aby znaleźć klejnot, znalazłem również dość kompletny przykład na tej stronie wiki . Składając je razem, ustaliłem następujący kod.

Przy okazji, polecenie instalacji gem jest: sudo gem install fastercsv (wszystkie małe litery)

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
 27
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 17:24:32

Inny sposób, aby to zrobić bez użycia FasterCSV:

Wymaga biblioteki CSV Rubiego w pliku inicjalizacyjnym, takim jak config/initializers / dependencies.rb

require "csv"

Jako tło poniższy kod jest oparty na zaawansowanym formularzu wyszukiwania Ryana Bate , który tworzy zasób wyszukiwania. W moim przypadku metoda Pokaż zasób wyszukiwania zwróci wyniki wcześniej zapisanego wyszukiwania. Reaguje również na csv i używa szablonu widoku do formatowania pożądanego wyjście.

  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

The show.csv.plik erb wygląda następująco:

<%- 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 -%>

W wersji html strony raportu mam link do eksportu raportu, który użytkownik przegląda. Poniżej znajduje się link_to, które zwraca wersję raportu csv:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
 26
Author: rwc9u,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-21 17:16:04

Spójrz na FasterCSV klejnot.

Jeśli potrzebujesz tylko obsługi programu excel, możesz również spojrzeć na generowanie xls bezpośrednio. (Patrz Arkusz Kalkulacyjny:: Excel)

gem install fastercsv
gem install spreadsheet-excel

Uważam, że te opcje są dobre do otwarcia pliku csv w Windows Excel:

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

Co do części ActiveRecord to coś takiego zrobi:

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
 7
Author: kch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 17:15:04

Musisz ustawić nagłówek Content-Type w odpowiedzi, a następnie wysłać dane. Content_Type: application / vnd. ms-excel powinien załatwić sprawę.

Możesz również ustawić nagłówek Content-Disposition tak, aby wyglądał jak dokument Excel, a przeglądarka wybiera rozsądną domyślną nazwę pliku; jest to coś w rodzaju Content-Disposition: attachment; filename= " #{suggested_name}.xls "

Sugeruję użycie klejnotu ruby fastercsv do wygenerowania pliku CSV, ale jest też wbudowany plik csv. Przykładowy kod fastercsv (z dokumentacji gem) wygląda tak:

csv_string = FasterCSV.generate do |csv|
  csv << ["row", "of", "CSV", "data"]
  csv << ["another", "row"]
# ...
end
 2
Author: JasonTrue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-18 17:16:28

Poniższe podejście działa dobrze w moim przypadku i powoduje, że przeglądarka otwiera odpowiednią aplikację dla typu CSV po pobraniu.

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
Author: rantler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-22 00:02:32

Wypróbuj ładny klejnot do generowania CSV z Rails https://github.com/crafterm/comma

 1
Author: Henry Jacob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-17 07:00:59

Spójrz na CSV Shaper gem.

Https://github.com/paulspringett/csv_shaper

Ma ładny DSL i działa naprawdę dobrze z modelami Rails. Obsługuje również nagłówki odpowiedzi i umożliwia dostosowywanie nazw plików.

 0
Author: paul,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-07-25 19:15:21

Jeśli po prostu chcesz samodzielnie pobrać bazę danych csv z konsoli, możesz to zrobić w kilku linijkach

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
Author: boulder_ruby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-07-19 01:34:51