2008-09-18 5 views
52

ich eine einfache Datenbanktabelle „Einträge“ genannt haben:in Schienen, wie die Datensätze als CSV-Datei zurückzukehren

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 

Wie schreibe ich einen Handler, der den Inhalt der Einträge Tabelle als CSV zurück Datei (idealerweise so, dass sie automatisch in Excel geöffnet wird)?

class EntriesController < ApplicationController 

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

    # ??? NOW WHAT ???? 

    end 

end 
+0

Zumindest in den neueren Versionen von Rails, können Sie auch 'Eintrag verwenden. alles stattdessen. –

Antwort

22

Es gibt ein Plugin namens FasterCSV, das dies wunderbar verarbeitet.

+29

Beachten Sie, dass ruby> = 1.9, FasterCSV jetzt die Standard-CSV-Bibliothek ist und nur CSV genannt wird. – kdt

+0

Der Schlüssel ist 'require 'csv'', siehe https://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html – mb21

7

Werfen Sie einen Blick in den Edelstein FasterCSV.

Wenn alles, was Sie benötigen, ist Excel-Unterstützung, können Sie auch in die Generierung einer xls direkt suchen. (Siehe Tabellenkalkulations :: Excel)

gem install fastercsv 
gem install spreadsheet-excel 

ich diese Optionen gut finde die CSV-Datei in Windows Excel zum Öffnen:

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

Was den Active Teil, so etwas wie dies tun würde:

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

Sie müssen den Content-Type-Header in Ihrer Antwort festlegen, dann senden Sie die Daten. Content_Type: application/vnd.ms-excel sollte den Trick machen.

Sie können auch den Content-Disposition-Header so einstellen, dass er wie ein Excel-Dokument aussieht, und der Browser wählt einen angemessenen Standarddateinamen aus; das ist so etwas wie Content-Disposition: Anhaftung; filename = "# {suggest_name} .xls"

Ich empfehle die Verwendung der firexcsv Ruby Gem, um Ihre CSV zu generieren, aber es gibt auch eine eingebaute CSV. Der fastercsv Beispielcode (aus der Dokumentation des gem) sieht wie folgt aus:

csv_string = FasterCSV.generate do |csv| 
    csv << ["row", "of", "CSV", "data"] 
    csv << ["another", "row"] 
# ... 
end 
+0

Danke für diesen obskuren Content-Type! Ich bin mir nicht sicher, ob es am Ende Excel sein wird, aber das ist gut zu wissen. – Eric

87

FasterCSV ist definitiv der Weg zu gehen, aber wenn Sie es direkt von Ihrer Rails-Anwendung dienen wollen, werden Sie einige einrichten möchten Antwortheader auch.

Ich halte eine Methode, um die Dateinamen und notwendigen Header einzurichten:

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 

verwenden, macht es einfach, so etwas in meinem Controller haben:

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

und habe einen Blick das sieht wie folgt aus: (generate_csv von FasterCSV ist)

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

Hmm, ich dachte, ich wäre fertig, bis ich deine Antwort gesehen habe! Danke für die Header-Details, ich werde mich an die erinnern, falls ich mit dem, was ich bisher benutzt habe, in Schwierigkeiten komme. – Eric

+8

Wie oben erwähnt, ist FasterCSV nur CSV in Ruby 1.9 und höher. Die gererate_csv-Methode ist jetzt CSV.generate. –

+4

Durch Hinzufügen von .html_safe am Ende des generate_csv/CSV.generate-Blocks wird dafür gesorgt, dass alle Kommata in den Daten ordnungsgemäß behandelt werden. Ohne diesen Aufruf hatte meine CSV-Datei eine Reihe von " " drin. – stcorbett

24

Ich akzeptierte (und stimmte!) @ Brians Antwort, weil sie mich zuerst auf FasterCSV zeigte. Dann, als ich gegoogelt habe, um den Edelstein zu finden, fand ich auch ein ziemlich vollständiges Beispiel bei this wiki page. Ich setzte sie zusammen und entschied mich für den folgenden Code.

By the way, der Befehl den Edelstein zu installieren ist: sudo gem install fastercsv (nur Kleinbuchstaben)

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 
+5

Ich würde vorschlagen, die CSV-Generation in eine Ansicht zu verschieben: das ist mehr Präsentationslogik als Sie normalerweise in einem Controller wünschen. –

+0

Sie können den Typ auf "Text/CSV" festlegen. Ansonsten speichert Safari es als 'entries.csv.txt' – silasjmatson

24

Ein anderer Weg, dies zu tun, ohne FasterCSV mit:

Rubys csv Erfordern Bibliothek in einer Initialisierer-Datei wie config/initializers/dependencies.rb

require "csv" 

Da einige Hintergrund der folgende Code basiert auf Ryan Bate's Advanced Search Form, die eine Suchressource erstellt. In meinem Fall gibt die show-Methode der Suchressource die Ergebnisse einer zuvor gespeicherten Suche zurück. Es reagiert auch auf CSV und verwendet eine Ansichtsvorlage, um die gewünschte Ausgabe zu formatieren.

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 

Die show.csv.erb Datei sieht wie folgt aus:

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

auf der HTML-Version des Berichts Seite ich einen Link, um den Bericht zu exportieren, dass der Benutzer sehen ist. Im Folgenden ist der link_to, die die CSV-Version des Berichts zurückgibt:

<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %> 
+5

Vergessen Sie nicht, '<% = CSV.generate_line (row) .html_safe%>' zu verwenden, wenn Sie Rails 3 verwenden, um zu vermeiden, dass Zeichen verloren gehen. – dombesz

+6

Diese Lösung funktioniert gut, aber ich musste die Einstellung CSV.generate_line Anrufe ändern: row_sep auf Null. Diese Änderung entfernt unerwünschte Leerzeilen aus der Antwort. Code: '<% = CSV.generate_line row, {: row_sep => nil}%>' –

+2

Um Wilsons Kommentar hinzuzufügen, fügt Heroku (Zedernholzstapel -beta) Leerzeilen in CSV-Dateien ein, es sei denn, Sie sagen es ausdrücklich nicht mit ': row_sep => nil'. – nslocum

2

Die genähert folgende funktionierte gut für meinen Fall und bewirkt, dass der Browser die entsprechende Anwendung für die CSV-Typ zu öffnen nach dem Download.

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 
1

versuchen, ein schönes Juwel CSV von Rails zu erzeugen https://github.com/crafterm/comma

+1

Gute Antwort, aber um es toll zu machen, vielleicht könnten Sie erklären, warum dieses Juwel (im Gegensatz zu anderen) –

0

Werfen Sie einen Blick auf die CSV-Shaper gem.

https://github.com/paulspringett/csv_shaper

Es hat einen schönen DSL und funktioniert wirklich gut mit Rails-Modelle. Es verarbeitet auch die Antwortheader und ermöglicht die Anpassung von Dateinamen.

0

Wenn Sie einfach nur wollen, sind die CSV-Datenbank Sie sich von der Konsole erhalten, können Sie dies in ein paar Zeilen

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(""))} 
Verwandte Themen