in rails, come restituire i record in un file csv
-
01-07-2019 - |
Domanda
Ho una semplice tabella di database chiamato "Voci":
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
Come faccio a scrivere un gestore che verrà restituito il contenuto delle Voci della tabella in un file CSV (idealmente in modo che si aprirà automaticamente in Excel)?
class EntriesController < ApplicationController
def getcsv
@entries = Entry.find( :all )
# ??? NOW WHAT ????
end
end
Soluzione
C'è un plugin chiamato FasterCSV che gestisce questo meravigliosamente.
Altri suggerimenti
FasterCSV è sicuramente il modo di andare, ma se si vuole servire direttamente dalla vostra applicazione Rails, è necessario impostare alcune intestazioni di risposta, troppo.
Ho un metodo per impostare il nome del file e header necessari:
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
L'utilizzo che la rende facile per avere qualcosa di simile nel mio controller:
respond_to do |wants|
wants.csv do
render_csv("users-#{Time.now.strftime("%Y%m%d")}")
end
end
E hanno una vista che assomiglia a questo:(generate_csv
è da 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 %>
Ho accettato (e votato up!) @Brian risposta, per la prima indicarmi FasterCSV.Poi, quando ho cercato su google per trovare la gemma, ho trovato anche un esempio abbastanza completo questa pagina wiki.Metterli insieme, ho risolto il codice riportato di seguito.
A proposito, il comando per installare la gemma è:sudo gem install fastercsv (tutto minuscolo)
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
Un altro modo per fare questo senza l'utilizzo di FasterCSV:
Richiedono ruby biblioteca csv in un file di inizializzazione, come config/inizializzatori/dipendenze.rb
require "csv"
Come background il codice riportato di seguito è basata fuori di Ryan Bate Avanzata Form di Ricerca che crea una risorsa di ricerca.Nel mio caso il metodo di presentazione di una ricerca risorsa dovrà restituire i risultati di una ricerca salvati in precedenza.Esso risponde al csv, e utilizza un modello di visualizzazione per il formato di output desiderato.
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
Lo show.csv.erb file è simile al seguente:
<%- 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 -%>
La versione html della pagina del report ho un link per esportare il report che l'utente sta visualizzando.Il seguente è il link_to che restituisce il csv versione del report:
<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
Prendere uno sguardo in FasterCSV gemma.
Se avete bisogno di excel di supporto, si potrebbe anche prendere in considerazione la generazione di un file xls direttamente.(Vedere Il Foglio Di Calcolo:Excel)
gem install fastercsv
gem install spreadsheet-excel
Trovo queste opzioni bene per l'apertura di un file csv in Windows Excel:
FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... }
Come per il ActiveRecord parte, qualcosa di simile a questo sarebbe fare:
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
È necessario impostare l'intestazione Content-Type in una tua risposta, quindi inviare i dati.Content_Type:application/vnd.ms-excel dovrebbe fare il trucco.
Si potrebbe anche voler impostare l'intestazione Content-Disposition in modo che appaia come un documento di Excel, e il browser preleva un ragionevole nome di file predefinito;che qualcosa come Content-Disposition:allegato;filename="#{suggested_name}.xls"
Io suggerisco di usare il fastercsv rubino per generare il tuo file CSV, ma c'è anche un builtin csv.Il fastercsv codice di esempio (da gemma documentazione) assomiglia a questo:
csv_string = FasterCSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
I seguenti avvicinato funzionato bene per il mio caso e fa sì che il browser per aprire l'applicazione appropriata per il CSV tipo dopo il 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
provare un bel gioiello per generare CSV Rotaie https://github.com/crafterm/comma
Date un'occhiata al CSV Shaper gemma.
https://github.com/paulspringett/csv_shaper
Ha un bel DSL e funziona davvero bene con Guide modelli.Gestisce inoltre le intestazioni di risposta e permette di nome di file di personalizzazione.
Se hai semplicemente voglia di ottenere il csv database manualmente dalla console è possibile farlo in poche righe
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(""))}