ruby-on-rails - guides - ruby on rails path




in rails, come restituire i record come file csv (7)

È necessario impostare l'intestazione Content-Type nella risposta, quindi inviare i dati. Content_Type: application / vnd.ms-excel dovrebbe fare il trucco.

Si consiglia inoltre di impostare l'intestazione Content-Disposition in modo che assomigli ad un documento Excel e il browser scelga un nome file predefinito ragionevole; è qualcosa come Content-Disposition: attachment; filename = "# {} suggested_name .xls"

Suggerisco di usare il rubino rubino più veloce per generare il tuo CSV, ma c'è anche un csv incorporato. Il codice di esempio quickcsv (dalla documentazione della gemma) ha il seguente aspetto:

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

Ho una semplice tabella di database chiamata "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 scrivo un gestore che restituirà il contenuto della tabella delle voci come un file CSV (idealmente in modo che si apra automaticamente in Excel)?

class EntriesController < ApplicationController

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

    # ??? NOW WHAT ????

  end

end

C'è un plugin chiamato FasterCSV che gestisce questo meravigliosamente.


Dai un'occhiata alla gemma CSV Shaper.

https://github.com/paulspringett/csv_shaper

Ha una bella DSL e funziona molto bene con i modelli Rails. Gestisce anche le intestazioni di risposta e consente la personalizzazione del nome file.


Ho accettato (e ho votato!) @ La risposta di Brian, per prima cosa mi ha indirizzato a FasterCSV. Poi, quando ho cercato su Google di trovare la gemma, ho trovato anche un esempio abbastanza completo su questa pagina wiki . Mettendoli insieme, ho optato per il seguente codice.

A proposito, il comando per installare la gemma è: sudo gem install fastercsv (tutto in 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

Se vuoi semplicemente ottenere il database CSV dalla console, puoi 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(""))}

Un altro modo per farlo senza utilizzare FasterCSV:

Richiede la libreria csv di ruby ​​in un file di inizializzazione come config / initializers / dependencies.rb

require "csv"

Come sfondo, il seguente codice si basa sul modulo di ricerca avanzata di Ryan Bate che crea una risorsa di ricerca. Nel mio caso il metodo show della risorsa di ricerca restituirà i risultati di una ricerca salvata in precedenza. Risponde anche a csv e utilizza un modello di visualizzazione per formattare l'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

Il file show.csv.erb ha il seguente aspetto:

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

Nella versione html della pagina del report ho un link per esportare il report che l'utente sta visualizzando. Quello che segue è il link_to che restituisce la versione csv del report:

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

FasterCSV è sicuramente la strada da percorrere, ma se vuoi servirlo direttamente dalla tua app Rails, ti consigliamo di impostare anche alcune intestazioni di risposta.

Tengo un metodo in giro per impostare il nome del file e le intestazioni necessarie:

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

Usarlo rende facile 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 avere una vista simile a questa: ( generate_csv è di 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 %>




csv