ruby on rails guides in rails, come restituire i record come file csv




ruby on rails path (8)

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

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.


Il seguente approccio ha funzionato bene per il mio caso e fa sì che il browser apra l'applicazione appropriata per il tipo CSV 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

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


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

Dai un'occhiata alla gemma FasterCSV .

Se tutto ciò di cui hai bisogno è il supporto di Excel, potresti anche cercare di generare direttamente un xls. (Vedi Foglio di calcolo :: Excel)

gem install fastercsv
gem install spreadsheet-excel

Trovo queste opzioni buone per l'apertura del file CSV in Windows Excel:

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

Per quanto riguarda la parte ActiveRecord, qualcosa del genere dovrebbe 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

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

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




csv