J'ai une table de base de données simple appelée "Entrées":
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
Comment puis-je écrire un gestionnaire qui renverra le contenu de la table des entrées sous forme de fichier CSV (idéalement de manière à ce qu'il s'ouvre automatiquement dans Excel)?
class EntriesController < ApplicationController
def getcsv
@entries = Entry.find( :all )
# ??? NOW WHAT ????
end
end
Il existe un plugin appelé FasterCSV qui gère cela à merveille.
FasterCSV est certainement le chemin à parcourir, mais si vous souhaitez le servir directement à partir de votre application Rails, vous voudrez également configurer des en-têtes de réponse.
Je garde une méthode pour configurer le nom de fichier et les en-têtes nécessaires:
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
En utilisant cela, il est facile d'avoir quelque chose comme ça dans mon contrôleur:
respond_to do |wants|
wants.csv do
render_csv("users-#{Time.now.strftime("%Y%m%d")}")
end
end
Et avoir une vue qui ressemble à ceci: (generate_csv
vient de 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 %>
J'ai accepté (et voté!) @ La réponse de Brian, pour m'avoir d'abord pointé sur FasterCSV. Ensuite, lorsque j'ai cherché sur Google pour trouver la gemme, j'ai également trouvé un exemple assez complet sur cette page wiki . En les assemblant, je me suis installé sur le code suivant.
Par ailleurs, la commande pour installer la gemme est: Sudo gem install fastcsv (tout en minuscules)
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
Une autre façon de le faire sans utiliser FasterCSV:
Requiert la bibliothèque csv de Ruby dans un fichier d'initialisation comme config/initializers/dependencies.rb
require "csv"
Comme arrière-plan, le code suivant est basé sur Formulaire de recherche avancée de Ryan Bate qui crée une ressource de recherche. Dans mon cas, la méthode show de la ressource de recherche retournera les résultats d'une recherche précédemment enregistrée. Il répond également à csv et utilise un modèle de vue pour formater la sortie souhaitée.
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
Le fichier show.csv.erb ressemble à ceci:
<%- 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 -%>
Sur la version html de la page du rapport, j'ai un lien pour exporter le rapport que l'utilisateur consulte. Voici le link_to qui renvoie la version csv du rapport:
<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
Jetez un œil à la gemme FasterCSV .
Si vous n'avez besoin que de la prise en charge d'Excel, vous pouvez également envisager de générer directement un xls. (Voir Feuille de calcul :: Excel)
gem install fastercsv
gem install spreadsheet-Excel
Je trouve ces options bonnes pour ouvrir le fichier csv dans Windows Excel:
FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... }
Quant à la partie ActiveRecord, quelque chose comme ça ferait:
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
L'approche suivante a bien fonctionné pour mon cas et amène le navigateur à ouvrir l'application appropriée pour le type CSV après le téléchargement.
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
Vous devez définir l'en-tête Content-Type dans votre réponse, puis envoyer les données. Content_Type: application/vnd.ms-Excel devrait faire l'affaire.
Vous pouvez également définir l'en-tête Content-Disposition de sorte qu'il ressemble à un document Excel et que le navigateur sélectionne un nom de fichier par défaut raisonnable; c'est quelque chose comme Content-Disposition: pièce jointe; filename = "# {suggest_name} .xls"
Je suggère d'utiliser le rapidcsv Ruby gem pour générer votre CSV, mais il y a aussi un csv intégré. L'exemple de code accelercsv (de la documentation du gem) ressemble à ceci:
csv_string = FasterCSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
essayez un joli bijou pour générer du CSV à partir de Rails https://github.com/crafterm/comma
Jetez un oeil à la gemme CSV Shaper.
https://github.com/paulspringett/csv_shaper
Il a une belle DSL et fonctionne très bien avec les modèles Rails. Il gère également les en-têtes de réponse et permet la personnalisation du nom de fichier.
Si vous voulez simplement obtenir la base de données csv vous-même depuis la console, vous pouvez le faire en quelques lignes
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(""))}