dans les rails, comment retourner des enregistrements dans un fichier csv
-
01-07-2019 - |
Question
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 renvoie le contenu du tableau Entries 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
La solution
Il existe un plugin appelé FasterCSV qui gère cela à merveille.
Autres conseils
FasterCSV est certainement la voie à suivre, mais si vous souhaitez le servir directement depuis votre application Rails, vous voudrez également configurer des en-têtes de réponse.
Je garde une méthode pour configurer le nom du 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 obtenez une vue ressemblant à ceci: ( generate_csv
provient 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 dirigé vers 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, j'ai choisi le code suivant.
Au fait, la commande pour installer la gem est la suivante: sudo bijou installer plus vite (tous 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 faire cela sans utiliser FasterCSV:
Requiert la bibliothèque csv de ruby ??dans un fichier d'initialisation tel que config / initializers / dependencies.rb
require "csv"
Comme référence, le code suivant est basé sur le 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 renverra les résultats d'une recherche précédemment enregistrée. Il répond également au format 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 se présente comme suit:
<%- 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 affiché par l'utilisateur. Voici le lien_to qui renvoie la version csv du rapport:
<%= link_to "Export Report", formatted_advertiser_search_path(@advertiser_search, :csv) %>
Consultez le FasterCSV , un joyau.
Si tout ce dont vous avez besoin, c'est du support Excel, vous pouvez également envisager de générer directement un xls. (Voir Tableur :: Excel)
gem install fastercsv
gem install spreadsheet-excel
Je trouve ces options utiles pour ouvrir le fichier csv dans Windows Excel:
FasterCSV.generate(:col_sep => ";", :row_sep => "\r\n") { |csv| ... }
En ce qui concerne la partie ActiveRecord, cela ressemblerait à ceci:
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
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 afin 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: attachement; nom_fichier = "# {nom suggéré} .xls"
Je suggère d’utiliser la gem ruby ??plus rapidement que vôtre pour générer votre fichier CSV, mais il existe également un fichier CSV intégré. L'exemple de code plus rapidecsv (tiré de la documentation de la gemme) se présente comme suit:
csv_string = FasterCSV.generate do |csv|
csv << ["row", "of", "CSV", "data"]
csv << ["another", "row"]
# ...
end
Ce qui suit a bien fonctionné dans mon cas et a amené 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
essayez un bon bijou pour générer du CSV à partir de Rails https://github.com/crafterm/comma
Jetez un coup d'œil à la gemme CSV Shaper.
https://github.com/paulspringett/csv_shaper
Il a un joli DSL et fonctionne vraiment 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 souhaitez simplement récupérer vous-même la base de données csv à partir de 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(""))}